Reputation: 593
I am trying to get a grasp on multi-thread programming in .NET.
I want to create 100 tasks in a for-loop, each task would sleep 1 sec then output the i it was created with and it's managed thread id. After all tasks finish I want to output the total time elapsed.
So I am running this simple code
private static void Main(string[] args)
{
List<Task> tasks = new List<Task>();
for (int i = 0; i < 100; i++)
{
tasks.Add(Task.Factory.StartNew(() =>
{
Thread.Sleep(1000);
Console.WriteLine(i.ToString() + " " + Thread.CurrentThread.ManagedThreadId);
}));
}
Stopwatch watch = new Stopwatch();
watch.Start();
var final = Task.Factory.ContinueWhenAll(tasks.ToArray(), doneTasks =>
{
watch.Stop();
Console.WriteLine("done in {0}", watch.Elapsed);
});
Console.ReadKey();
}
The output I get:
100 24
100 23
...
100 14
100 25
done in 00:00:12.0044853
I don't understand why all the i's are same, and why 100? Intuitively I would expect them to be 0~99, but not all 100's.
Upvotes: 2
Views: 3413
Reputation: 34189
Imagine the order of execution. You instruct every task to output i
after a second, but by that time the loop has finished execution and i
is equal to 100.
You can use the following StartNew
overload to pass a state
object which will be used by your action:
public Task StartNew(Action<object> action, object state)
And do the following:
for (int i = 0; i < 100; i++)
{
tasks.Add(Task.Factory.StartNew(o =>
{
int value = (int)o;
Thread.Sleep(1000);
Console.WriteLine(value.ToString() + " " + Thread.CurrentThread.ManagedThreadId);
}, i));
}
Upvotes: 10
Reputation: 9425
That is because your tasks are being created before your closure gets executed. If you copy the value of I to a variable before the sleep call, or better yet, pass it as a parameter to your action, you should get the desired result.
Upvotes: 3