I have the following method:
static Random rr = new Random();
static void DoAction(Action a)
{
ThreadPool.QueueUserWorkItem(par =>
{
Thread.Sleep(rr.Next(200));
a.Invoke();
});
}
now I call this in a for loop like this:
for (int i = 0; i < 10; i++)
{
var x = i;
DoAction(() =>
{
Console.WriteLine(i); // scenario 1
//Console.WriteLine(x); // scenario 2
});
}
in scenario 1 the output is: 10 10 10 10 ... 10
in scenario 2 the output is: 2 6 5 8 4 ... 0
(random permutation of 0 to 9)
How do you explain this? Is c# not supposed to preserve variables (here i
) for the anonymous delegate call?
The problem here is that there is one i
variable and ten instances / copies of x
. Each lambda gets a reference to the single variable i
and one of the instances of x
. Every x
is only written to once and hence each lambda sees the one value which was written to the value it references.
The variable i
is written to until it reaches 10. None of the lambdas run until the loop completes so they all see the final value of i
which is 10
I find this example is a bit clearer if you rewrite it as follows
int i = 0; // Single i for every iteration of the loop
while (i < 10) {
int x = i; // New x for every iteration of the loop
DoAction(() => {
Console.WriteLine(i);
Console.WriteLine(x);
});
i++;
};
DoAction
spawns the thread, and returns right away. By the time the thread awakens from its random sleep, the loop will be finished, and the value of i
will have advanced all the way to 10. The value of x
, on the other hand, is captured and frozen before the call, so you will get all values from 0
to 9
in a random order, depending on how long each thread gets to sleep based on your random number generator.
I think you'll get the same result with java or any Object oriented Language (not sure but here it seems logical).
The scope of i
is for the whole loop and the scope of x
is for each occurrence.
Resharper helps you top spot this kind of problem.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With