2

i start 4 threads in a loop. each thread gets a reference to an array element to write the result.

But on the line where i create each thread, i get a System.IndexOutOfRangeException. I'm amazed that the index "i" is going out of range.

here is an example:

void ThreadsStarter()
{
    double[] data = new double[4];

    for(int i = 0; i < 4; i++)
    {
        Thread my_thread = new Thread(() => Work(data[i]));
        my_thread.Start();
    }
}

void Work(double data)
{
}

Why this is happening?

3
  • 2
    You are "closing over the loop variable" Commented Jul 21, 2013 at 0:38
  • I've removed ref from your sample/title as unrelated to the question - feel free to edit/rollback. Note ref is generally hard to use/understand, especially when you start using more flexible collections like List<double> instead of Array. Try to avoid ref - i.e. in this case Tuple.Create(data, i) could be an option (obviously created before lambda to avoid problem you have now). Commented Jul 21, 2013 at 0:50
  • thanks. now i also know the name of that construction (closures/lambdas). i do try to avoid ref. i will consider using tuples instead, this seems cleaner. that's a good article Blorgbeard. Commented Jul 21, 2013 at 1:29

1 Answer 1

6

This is a common error: i gets evaluated when threads starts, which happens after the loop has ended. Make a temp, assign i to it, and use temp instead of i in your lambda to fix the issue:

void ThreadsStarter()
{
    double[] data = new double[4];

    for(int i = 0; i < 4; i++)
    {
        var temp = i;
        Thread my_thread = new Thread(() => Work(ref data[temp]));
        my_thread.Start();
    }
}

void Work(ref double data)
{
}
Sign up to request clarification or add additional context in comments.

1 Comment

This works because when you recreate a temp variable, the compiler detects that the closure is "attached" to a different variable on every loop pass and will generate a "new DisplayClass()" code (which encapsulates the closure) inside every pass. Without temp variable it'll use the same DisplayClass (which holds a member of the i variable) from within all loop passes. (Similar to the code that c# 5 generates for a foreach loop - see an example here).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.