1

The following code does not work as I expect it. What am I doing wrong? Output is different on every run. Is there a better way of doing this? Assume action does something more complex than what's below.

Action<int> action = (int m) =>
{
    if ((m % 2) == 0)
        Console.WriteLine("Even");
    else
        Console.WriteLine("Odd");
};

const int n = 10;
Task[] tasks = new Task[n];
for (int i = 0; i < n; i++)
{
    tasks[i] = Task.Factory.StartNew(() => action(i+1));
}
Task.WaitAll(tasks);
Tigran
  • 872
  • 1
  • 9
  • 25

1 Answers1

3

The lambda in your loop is capturing a reference to the same i variable every time through the loop, not its value.

Change your loop to something like:

for (int i = 0; i < n; i++)
{
    var j = i;
    tasks[i] = Task.Factory.StartNew(() => action(j+1));
}

Note that the output will still be different on every run, but you should get exactly five even and five odd outputs.

Cameron
  • 96,106
  • 25
  • 196
  • 225
  • 1
    Related to answer: http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx – Matthew Feb 20 '14 at 22:24
  • Thanks Cameron. Great answer. And thanks for the link as well. – Tigran Feb 20 '14 at 22:36
  • 1
    Thought I'd show this too http://stackoverflow.com/questions/14907987/access-to-foreach-variable-in-closure. It's worth noting that the behavior you see here will vary on compiler version. On .net 4.5 you wouldn't have had this issue since they changed how the closures work – devshorts Feb 20 '14 at 22:56