Here is a sample code. Can you guess what the output would be ?
If you are using Resharper, it will give you a warning "Access to modified closure". I can't explain it better than here https://www.jetbrains.com/help/resharper/AccessToModifiedClosure.html
So the solution to above issue is to copy the value of i to a local variable with the loop as shown here
and now you get the correct result
Pat yourself if your answer was like thispublic static class TasksExample { public static void Execute() { Task[] tasks = new Task[10]; for (int i = 0; i < 10; i++) { tasks[i] = Task.Run(() => CalculateResult(i)); } Task.WaitAll(tasks); //ask.Wait(); //Console.WriteLine(tasks[i].Result); Console.WriteLine("Next work..."); } public static int CalculateResult(int i) { Console.WriteLine($"work starting {i}"); Thread.Sleep(10000); Console.WriteLine($"Completed work {i}"); return 100; } }
so why is this? For loop is iterating nicely but why did all the tasks got value 10? The answer lies in Closure and Captured variable. The scope of i is in for loop. When you pass the variable to an anonymous function, it wont use the value until the function is executed. In this case it is after the for loop has exited and now the value of i is 10. Hence when Task executes CalculateResult, all tasks now will have value 10. Awesome!!!work starting 10 work starting 10 work starting 10 work starting 10 work starting 10 work starting 10 work starting 10 work starting 10 work starting 10 work starting 10 Completed work 10 Completed work 10 Completed work 10 Completed work 10 Completed work 10 Completed work 10 Completed work 10 Completed work 10 Completed work 10 Completed work 10 Next work...
If you are using Resharper, it will give you a warning "Access to modified closure". I can't explain it better than here https://www.jetbrains.com/help/resharper/AccessToModifiedClosure.html
So the solution to above issue is to copy the value of i to a local variable with the loop as shown here
public static class TasksExample { public static void Execute() { Task[] tasks = new Task[10]; for (int i = 0; i < 10; i++) { var i1 = i; tasks[i] = Task.Run(() => CalculateResult(i1)); } Task.WaitAll(tasks); //ask.Wait(); //Console.WriteLine(tasks[i].Result); Console.WriteLine("Next work..."); } public static int CalculateResult(int i) { Console.WriteLine($"work starting {i}"); Thread.Sleep(10000); Console.WriteLine($"Completed work {i}"); return 100; } }
and now you get the correct result
work starting 1 work starting 0 work starting 2 work starting 3 work starting 4 work starting 5 work starting 6 work starting 7 work starting 8 work starting 9 Completed work 1 Completed work 2 Completed work 3 Completed work 0 Completed work 5 Completed work 4 Completed work 6 Completed work 7 Completed work 8 Completed work 9 Next work...
Comments