TheLegendaryCopyCoder
TheLegendaryCopyCoder

Reputation: 1832

Launching multiple threads, Why must you wait?

I have been playing around with Threads and Tasks (.net 4) and noticed some odd behavior when you launch multiple threads without waiting a few miliseconds between each thread started call.

The example below when run does not output what I expected:

1
2
1
2

But instead only outputs:

2
2
2
2

Below is the code that I am running.

public static void Main()
{
    var items = new[] {"1", "2"};
    foreach (var item in items)
    {
      var thread = new Thread(() => Print(item));          
      thread.Start();
      //var task = Task.Factory.StartNew(() => Print(item));               
    }
}

static void Print(string something)
{
  while (true)
  {
    Console.WriteLine(something);
    Thread.Sleep(1000);
  }
}

Now when I call Thread.Sleep(50) after the thread.Start() then only does the output look as expected

1
2
1
2

My question is:

i.e. first thread is launched with parameter of "1", second thread is launched with parameter of "2", however first thread's parameter becomes "2" as well? This makes no sense, especially since Print() method paramter is a value type of string.

Upvotes: 1

Views: 174

Answers (4)

Emond
Emond

Reputation: 50672

Show us the thread starting code and you'll find that you do not pass a constant string but a reference variable and in between calling those Start methods you are probably changing the variable.

Upvotes: 0

Kell
Kell

Reputation: 3317

The item is evaluated at the time that the thread you create starts due to c# closures. Another way to force the item to evaluate is to introduce a variable so that the closure will include it like so:

foreach (var item in items)     
        {
            var closedItem = item;
            var thread = new Thread(() => Print(closedItem));                 
            thread.Start();       
        } 

Upvotes: 2

Stilgar
Stilgar

Reputation: 23551

Your problem is not with threads. Your problem is with the closure and the foreach. You can read here why: http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx

When you play with the timing of the threads you reorder the timings of the main thread as well so sometimes the loop will be executed before the print method of the new thread runs and sometimes after.

Upvotes: 1

Kevin
Kevin

Reputation: 1005

Google "access to modified closure". What's happening is your local variable "item" is getting it's value changed before the Print function is invoked. A solution would be to create a new variable inside the scope of the loop and assign item to it.

Upvotes: 5

Related Questions