Reputation: 45096
When I run the following I get the value of 100 for Task #{0} and cb
If I debug line by line in the loop then I get the correct answer.
How to fix this?
public static void TaskList()
{
ConcurrentBag<int> cb = new ConcurrentBag<int>();
List<Task> taskArray = new List<Task>();
for (int i = 0; i < 100; i++)
{
taskArray.Add(Task.Factory.StartNew((Object obj) => {
int j = 0 + i;
cb.Add(j);
Debug.WriteLine("Task #{0} created on {1}",
j, Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(10);
},
i));
}
Task.WaitAll(taskArray.ToArray());
foreach(var v in cb)
{
Debug.WriteLine(v);
}
Debug.WriteLine("");
}
Upvotes: 0
Views: 53
Reputation: 789
You're seeing 100
getting print out for almost every run because the i
in the following line is equivalent to 100 by the time the tasks are getting run:
int j = 0 + i;
I believe you're attempting to alleviate this problem with your int j = 0 + i
line, but since the i
is what's getting changed, j
will still always be equivalent to whatever i
is when the task is run. If you assign the value of i
to j
outside of your task, then you won't see this issue:
int j = i;
taskArray.Add(Task.Factory.StartNew((Object obj) => {
cb.Add(j);
Console.WriteLine("Task #{0} created on {1}",
j, Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(10);
}, , i));
Not sure I did a great job of explaining that, but I hope it helps.
Upvotes: 1
Reputation: 18265
You are passing a modified closure (i
) inside your tasks.
When the Task
is effectively executed the value of i
is not determinated (in your case, it is 100 because the task starts after your for
loop finishes).
You must avoid to capture modified closures inside delegates which are executed lazily (your Task
snippet is an example, but the same could happen using LINQ on IEnumerable
).
Instead, assign your value to a local variable and pass it inside the Task
action:
for (int i = 0; i < 100; i++)
{
var count = i;
taskArray.Add(Task.Factory.StartNew((Object obj) => {
int j = 0 + count;
cb.Add(j);
Debug.WriteLine("Task #{0} created on {1}",
j, Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(10);
},
i));
}
Upvotes: 3