Reputation: 1843
I have these two implementations of the seemingly identical loop:
List<Type> types = ...
tasks = new Task<List<TypeInfo>>[types.Count];
for (Int32 i = 0; i < types.Count; i++)
{
tasks[i] = Task<List<TypeInfo>>.Run(() => GetBaseTypeList(types[i]));
}
Task.WaitAll(tasks);
When I do this, it could happen that I get an IndexOutOfRangeException
because when the asynchronous task is started, i
could have any value by now.
So far I do understand the mechanics behind it.
What I don't understand is, why this works:
List<Type> types = ...
tasks = new Task<List<TypeInfo>>[types.Count];
for (Int32 i = 0; i < types.Count; i++)
{
Type t;
//do not put the indexer types[i] directly into the call because when the task is executed, i can have any value (delayed execution!).
t = types[i];
tasks[i] = Task<List<TypeInfo>>.Run(() => GetBaseTypeList(t));
}
Task.WaitAll(tasks);
t
is also changed during each loop but why do all the task perfectly execute with the t
that was assigned during that loop iteration?
Upvotes: 1
Views: 84
Reputation: 116558
t
is not changed during the loop.
t
is a local variable inside the scope of the for
loop, which basically means that it's a "new" t
for each iteration.
i
on the other hand lives through all iterations of the for
loop (otherwise it would be 0 each iteration) and beyond which is why it's changed in each iteration and shouldn't be closed over.
For example, in the second iteration after Type t;
t
's value is null
and not the type from the previous iteration.
Upvotes: 4
Reputation: 17485
You have to understand closures. Even it has difference between how delegate capture variable of loop.
when you first loop executed it may possible that Task is wait for execution and by that time value of i get increased or may be end of loop and wait for all task to finish. At that point if task run then it try to execute types[i] which obiviously out of index in some case.
for (Int32 i = 0; i < types.Count; i++)
{
tasks[i] = Task<List<TypeInfo>>.Run(() => GetBaseTypeList(types[i]));
}
For your second loop you first copy it to local variable of loop and that get captured so when task run it does not have to depend on value of i.
You will find more information over here. http://csharpindepth.com/articles/chapter5/closures.aspx
Upvotes: 1