1

I am defining a jagged array of threads (such that each thread can operate on the directory tree of its own) in this manner

Task[][] threads = new Task[InstancesDir.Length][];
for (int i = 0; i < InstancesDir.Length; i++)
{
    threads[i] = new Task[InstancesDir[i].Length];
}
for (int i = 0; i < FilesDir.Length; i++)
{
    for (int j = 0; j < FilesDir[i].Length; j++)
    {
        threads[i][j] = Task.Run(() =>
        {
            Calculate(i, j, InstancesDir, FilesDir, PointSum);
        });
    }
    Task.WaitAll(threads[i]);
}

But in calculate i always get value of j >= FilesDir[i].Length . I have also checked that objects are passed by value except arrays. What could be a workaround for this and what could be the reason for this behavior?

PS. Introducing a shared lock might help in mitigation the concurrency issue but i want to know about the reason for such behavior.

Justin
  • 84,773
  • 49
  • 224
  • 367

1 Answers1

3

But in calculate i always get value of j >= FilesDir[i].Length

This isn't a concurrency issue, as your for loop is executing on a single thread. This happens because the lambda expression is closing over your i and j variables. This effect is called Closure.

In order to avoid it, create a temp copy before passing both variables to Task.Run:

var tempJ = j;
var tempI = i;

threads[tempI][tempJ] = Task.Run(() =>
{
    Calculate(tempI, tempJ, InstancesDir, FilesDir, PointSum);
});
Community
  • 1
  • 1
Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
  • Actually, if I'm not mistaken, this is due to the fact that there is a peculiar "bug" in C# with regards to closures and loop variables (which incidentally is worked around using variables declared inside the loop, such as you do with your temp variables). – Alxandr Feb 04 '15 at 07:02
  • 1
    I wouldn't say this is a bug. This is by design. See [this](http://csharpindepth.com/Articles/Chapter5/Closures.aspx) – Yuval Itzchakov Feb 04 '15 at 07:03
  • I actually expect this to be by accident, since any other variable (as far as I know), except loop variables, behave differently (and get's properly closed over if you use them in the closure), but I might be wrong, and it might be a weird perf thing. I just find it weird that first of all the behave differently, and second of all they by choice wandered into the pitfall of loops and closures you have in javascript. – Alxandr Feb 04 '15 at 07:08