You grabbed the loop variable i , which can lead to the use of the last value of βiβ when each thread ultimately executes and retrieves data from threadData . Assign i variable in a loop and use this instead, for example:
Thread [] threads = new Thread[threadData.Length]; for (int i = 0; i < threadData.Length; i++) { int index = i; threads[i]= new System.Threading.Thread(() => threadWork(threadData[index])); threads[i].Start(); }
Eric Lippert has a very good article on the phenomenon here:
http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx
http://blogs.msdn.com/b/ericlippert/archive/2009/11/16/closing-over-the-loop-variable-part-two.aspx
To understand why this is happening, think that threads will run at some undefined point in the future, possibly after the loop ends. Start signals that the thread should start, it actually starts asynchronously, but not immediately. Given this, we can see that the lambda passed to Thread can perform well after the loop finishes. So how can it refer to i ?
In short, the compiler will create a helper class that can encapsulate i , and then replace the references to i with this helper class. This allows the lambda to have a reference to i outside the scope of the loop. A good example of compiler magic, but in this case has an unobvious side effect, i.e. it captures a loop variable:
private class LambdaHelper { public int VarI { get; set; } } private static void SomeMethod() { LambdaHelper helper = new LambdaHelper(); Thread[] threads = new Thread[threadData.Length]; for (helper.VarI = 0; helper.VarI < data.Length; helper.VarI++) { threads[helper.VarI] = new Thread(() => ThreadWork(data[helper.VarI])); threads[helper.VarI].Start(); } }
Here we see that VarI used instead of i . An unobvious side effect is that when threads execute, they all see a common meaning, i.e. VarI . If threads start after the loop finishes, they will all see the maximum value of i .
The fix is ββto assign i temporary variable inside the loop, as described in the first code example.