473,395 Members | 1,666 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,395 software developers and data experts.

Anonymous Methods As ThreadStarts

I read an article that had a really elegant solution to pass parameters
to a thread by using an anonymous method as your ThreadStart. It
seemed pretty slick and even worked when I tried it. However, with
some more playing around, I got some really strange results. Using the
code below, sometimes my output is 2 and 3. Sometimes, it's 3 and 3.
However, it's never been 1 and 2 which is what I would expect. Can
anybody set me straight on why I'm getting the unexpected results? My
suspicion is that somehow my integer is getting passed by reference
rather than value, but I'd like someone else to corroborate that before
I go on believing it. (Note: I know about ParameterizedThreadStart.
I'm just trying to use this example to understand anonymous methods a
little better.)

namespace AnonymousConfusion
{
class Program
{
static void Main(string[] args)
{
int i = 1;

ThreadStart ts1 = delegate { WorkThread(i); };
Thread t1 = new Thread(ts1);
// i should be 1 when i'm starting my thread, right?
t1.Start();

i++;

ThreadStart ts2 = delegate { WorkThread(i); };
Thread t2 = new Thread(ts2);
// i should 2 when i'm starting my thread, right?
t2.Start();

i++;

t1.Join();
t2.Join();

// why am i getting 2 and 3 or sometimes 3 and 3 for
output?
Console.WriteLine("Done");
Console.ReadLine();
}

static void WorkThread(int i)
{
Console.WriteLine(i.ToString());
}
}
}

Mar 10 '06 #1
7 2215
This has nothing to do with Anonymous methods, other than the fact that you
used an anonymous method to create the threads.

The nature of threads is that they run independently of each other and of
the parent thread. Therefore, the time it takes for each thread to process
is in no way related to the order in which they are created.

--
HTH,

Kevin Spencer
Microsoft MVP
..Net Developer

Presuming that God is "only an idea" -
Ideas exist.
Therefore, God exists.

<d2*****@yahoo.com> wrote in message
news:11**********************@i39g2000cwa.googlegr oups.com...
I read an article that had a really elegant solution to pass parameters
to a thread by using an anonymous method as your ThreadStart. It
seemed pretty slick and even worked when I tried it. However, with
some more playing around, I got some really strange results. Using the
code below, sometimes my output is 2 and 3. Sometimes, it's 3 and 3.
However, it's never been 1 and 2 which is what I would expect. Can
anybody set me straight on why I'm getting the unexpected results? My
suspicion is that somehow my integer is getting passed by reference
rather than value, but I'd like someone else to corroborate that before
I go on believing it. (Note: I know about ParameterizedThreadStart.
I'm just trying to use this example to understand anonymous methods a
little better.)

namespace AnonymousConfusion
{
class Program
{
static void Main(string[] args)
{
int i = 1;

ThreadStart ts1 = delegate { WorkThread(i); };
Thread t1 = new Thread(ts1);
// i should be 1 when i'm starting my thread, right?
t1.Start();

i++;

ThreadStart ts2 = delegate { WorkThread(i); };
Thread t2 = new Thread(ts2);
// i should 2 when i'm starting my thread, right?
t2.Start();

i++;

t1.Join();
t2.Join();

// why am i getting 2 and 3 or sometimes 3 and 3 for
output?
Console.WriteLine("Done");
Console.ReadLine();
}

static void WorkThread(int i)
{
Console.WriteLine(i.ToString());
}
}
}

Mar 10 '06 #2
This makes perfect sense; the "i" in the anonymous delegate (I'm not on
about WorkThread here, just the bit in the braces) is the same i - and it
all depends on timing:

[thread 1] i=1
[thread 1] go to start a thread
[thread 1] increment i (now = 2)
[thread 2] catches up, call WorkThread with i, currently 2
[thread 1] go to start a thread
[thread 1] increment i (now = 3)
[thread 3] catches up, call WorkThread with i, currently 3

or

[thread 1] i=1
[thread 1] go to start a thread
[thread 1] increment i (now = 2)
[thread 1] go to start a thread
[thread 1] increment i (now = 3)
[thread 2] catches up, call WorkThread with i, currently 3
[thread 3] catches up, call WorkThread with i, currently 3

In a way, you have been lucky; this type of usage could also lead to
completely phantom reads of i, particularly if i is of a larger data-type
(long etc); for this (latter) reason you should *always* sync access to
variables when using multiple threads.

But the main behaviour makes perfect sense

Marc

<d2*****@yahoo.com> wrote in message
news:11**********************@i39g2000cwa.googlegr oups.com...
I read an article that had a really elegant solution to pass parameters
to a thread by using an anonymous method as your ThreadStart. It
seemed pretty slick and even worked when I tried it. However, with
some more playing around, I got some really strange results. Using the
code below, sometimes my output is 2 and 3. Sometimes, it's 3 and 3.
However, it's never been 1 and 2 which is what I would expect. Can
anybody set me straight on why I'm getting the unexpected results? My
suspicion is that somehow my integer is getting passed by reference
rather than value, but I'd like someone else to corroborate that before
I go on believing it. (Note: I know about ParameterizedThreadStart.
I'm just trying to use this example to understand anonymous methods a
little better.)

namespace AnonymousConfusion
{
class Program
{
static void Main(string[] args)
{
int i = 1;

ThreadStart ts1 = delegate { WorkThread(i); };
Thread t1 = new Thread(ts1);
// i should be 1 when i'm starting my thread, right?
t1.Start();

i++;

ThreadStart ts2 = delegate { WorkThread(i); };
Thread t2 = new Thread(ts2);
// i should 2 when i'm starting my thread, right?
t2.Start();

i++;

t1.Join();
t2.Join();

// why am i getting 2 and 3 or sometimes 3 and 3 for
output?
Console.WriteLine("Done");
Console.ReadLine();
}

static void WorkThread(int i)
{
Console.WriteLine(i.ToString());
}
}
}

Mar 10 '06 #3
> I read an article that had a really elegant solution to pass
parameters to a thread by using an anonymous method as your
ThreadStart. It seemed pretty slick and even worked when I tried it.
However, with some more playing around, I got some really strange
results. Using the code below, sometimes my output is 2 and 3.
Sometimes, it's 3 and 3. However, it's never been 1 and 2 which is


If you take a look using Reflector or some other disassembly tool you'll
notice that a method that declares an anonymous method and has local variables
that is used in that method will have some "magic" code in it. Basically
what happens is that a class to hold the method is defined, and the local
variables in your outer method is stored in that class. When the method starts,
an object is constructed from that class and used internally. As such, your
thread(s) and outer method shares the same variables with each other. This
means that you get all the features of sharing variables easily and all the
headache when doing so with threads.

Let me show you an actual example:

public void Test()
{
String s = String.Empty;
System.Threading.ThreadStart ts = delegate
{
s = "Set in delegate";
};
ts();
System.Diagnostics.Debug.WriteLine(s);
}

The decompiled version of this looks like this:

public void Test()
{
MainForm.<>c__DisplayClass1 class1 = new MainForm.<>c__DisplayClass1();
class1.s = string.Empty;
ThreadStart start1 = new ThreadStart(class1.<Test>b__0);
start1();
Debug.WriteLine(class1.s);
}

and then:

[CompilerGenerated]
private sealed class <>c__DisplayClass1
{
// Methods
public <>c__DisplayClass1() { }
public void <Test>b__0()
{
this.s = "Set in delegate";
}

// Fields
public string s;
}

So, as Kevin noted, the threads all work on the same variable and might not
even get scheduled some time before you increment the variable and start
the next thread, and that's why you get those results.

--
Lasse Vågsæther Karlsen
http://usinglvkblog.blogspot.com/
mailto:la***@vkarlsen.no
PGP KeyID: 0x2A42A1C2
Mar 10 '06 #4
d2*****@yahoo.com wrote:
I read an article that had a really elegant solution to pass parameters
to a thread by using an anonymous method as your ThreadStart. It
seemed pretty slick and even worked when I tried it. However, with
some more playing around, I got some really strange results. Using the
code below, sometimes my output is 2 and 3. Sometimes, it's 3 and 3.
However, it's never been 1 and 2 which is what I would expect. Can
anybody set me straight on why I'm getting the unexpected results? My
suspicion is that somehow my integer is getting passed by reference
rather than value, but I'd like someone else to corroborate that before
I go on believing it.


It's not that it's being "passed" so much as that it's being shared
between the delegates. It's a captured variable - not really a local
variable any more.

See http://www.pobox.com/~skeet/csharp/c...delegates.html for more
information and a really scary example...

Jon

Mar 10 '06 #5

<d2*****@yahoo.com> wrote in message
news:11**********************@i39g2000cwa.googlegr oups.com...
|I read an article that had a really elegant solution to pass parameters
| to a thread by using an anonymous method as your ThreadStart. It
| seemed pretty slick and even worked when I tried it. However, with
| some more playing around, I got some really strange results. Using the
| code below, sometimes my output is 2 and 3. Sometimes, it's 3 and 3.
| However, it's never been 1 and 2 which is what I would expect. Can
| anybody set me straight on why I'm getting the unexpected results? My
| suspicion is that somehow my integer is getting passed by reference
| rather than value, but I'd like someone else to corroborate that before
| I go on believing it. (Note: I know about ParameterizedThreadStart.
| I'm just trying to use this example to understand anonymous methods a
| little better.)
|
| namespace AnonymousConfusion
| {
| class Program
| {
| static void Main(string[] args)
| {
| int i = 1;
|
| ThreadStart ts1 = delegate { WorkThread(i); };
| Thread t1 = new Thread(ts1);
| // i should be 1 when i'm starting my thread, right?
| t1.Start();
|
| i++;
|
| ThreadStart ts2 = delegate { WorkThread(i); };
| Thread t2 = new Thread(ts2);
| // i should 2 when i'm starting my thread, right?
| t2.Start();
|
| i++;
|
| t1.Join();
| t2.Join();
|
| // why am i getting 2 and 3 or sometimes 3 and 3 for
| output?
| Console.WriteLine("Done");
| Console.ReadLine();
| }
|
| static void WorkThread(int i)
| {
| Console.WriteLine(i.ToString());
| }
| }
| }
|

Before your thread gets actually a chance to run and pick up the value of i,
your main thread will have incremented the value once maybe twice.

Willy.

Mar 10 '06 #6
To get expected results, you could pass i instead of using local var capture.

Note that t2 could still complete before t1, but they should still have the expected i.

private void button3_Click(object sender, EventArgs e)

{

int i = 1;

Thread t1 = new Thread(WorkThread);

t1.Name = "t1";

t1.Start(i);

i++;

Thread t2 = new Thread(WorkThread);

t2.Name = "t2";

t2.Start(i);

i++;

t1.Join();

t2.Join();

}

static void WorkThread(object i)

{

Console.WriteLine("Thread:{0} Value:{1}", Thread.CurrentThread.Name, (int)i);

}
--
William Stacey [MVP]

Mar 10 '06 #7
Thanks. I got what I was looking for.

Mar 10 '06 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
by: Cordell Lawrence | last post by:
Okay guys, We are wondering if this is a bug in Framework 2.0.40607 and looking for some clarification on the issue. Take a look at the folowing code. public delegate bool BoundryTest(int...
9
by: John Smith | last post by:
I really can not appreciate why Microsoft has introduced Anonymous methods. It promotes quick and dirty style of programming and as I can see it offers no advantages over normal methods. I have...
7
by: Alexandre | last post by:
cross post: Hi can someone justify the use of these anonymous methods in C# 2.0 & 3.0 ? I simply do not see a use for them. can you show me an instance where thay can be useful ?? best...
7
by: Bill Woodruff | last post by:
I've found it's no problem to insert instances of named delegates as values into a generic dictionary of the form : private Dictionary<KeyType, DelegatemyDictionary = new Dictionary<KeyType,...
22
by: PJ6 | last post by:
I just learned about anonymous methods and was taken aback to discover that they are only available in C#. What, is there still a stigma against VB.Net, that maybe somehow this is a language that...
4
by: Frankie | last post by:
I have just gotten up to speed on what anonymous methods are (syntax, capabilities, etc), and how they can be used with /called via delegates. What I am wondering is... 1. Are they only/mostly...
2
by: Tony | last post by:
Hello! Here I have some text from a book I read. It says: "An interesting point to note concerning anonymous methods is that they are effectively local to the code block that contains them, and...
0
by: Peter Duniho | last post by:
On Mon, 01 Sep 2008 16:14:10 -0700, Blip <blip@krumpli.comwrote: Briefly, an anonymous method is exactly that: a method without a name. When you use the "delegate" keyword to declare an...
4
by: Peter | last post by:
Hi I've been delving into "delegates" and "anonymous methods", and now I've come across the term "closure". Some information I've found says that C# does not have closures, other information...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.