11

i have this code:

    Thread[] threadsArray = new Thread[4];
        for (int i = 0; i < 4; i++)
        {
            threadsArray[i] = new Thread(() => c1.k(i));
        }
        for (int i = 0; i < 4; i++)
        {
            threadsArray[i].Start();
        }
        for (int i = 0; i < 4; i++)
        {
            threadsArray[i].Join();
        }

the function k is this:

void k(int i)
{
    while(true)
      Console.WriteLine(i);
}

for some reason just the last thread is running and printing 4444444.... why aren't all the threads running?

Kyle Rosendo
  • 25,001
  • 7
  • 80
  • 118
aharon
  • 7,393
  • 10
  • 38
  • 49
  • 9
    This has to be the most oddball variant of the standard closing-over-the-loop-variable question I've ever seen. – Adam Robinson Jul 19 '10 at 20:51
  • This one is even more similar: http://stackoverflow.com/questions/1930133/c-closures-why-is-the-loopvariable-captured-by-reference – Mark Byers Jul 19 '10 at 21:06
  • Related: "Closing over the loop variable considered harmful" by Eric Lippert. http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx – Mark Byers Jul 20 '10 at 07:56
  • i is a captured outer variable in this context. See http://en.csharp-online.net/ECMA-334:_14.5.15.3.1_Captured_outer_variables – VVS Jul 20 '10 at 13:43

3 Answers3

30

All of the threads are printing the same variable.

Your lambda expression (() => c1.k(i)) captures the i variable by reference.
Therefore, when the lambda expression runs after i++, it picks up the new value of i.

To fix this, you need to declare a separate variable inside the loop so that each lambda gets its own variable, like this:

    for (int i = 0; i < 4; i++)
    {
        int localNum = i;
        threadsArray[i] = new Thread(() => c1.k(localNum));
    }
SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • 3
    +1 for this answer. It's basically the same as Winston's, but the explanation is more detailed. – schnaader Jul 19 '10 at 20:53
  • On a side note: some languages like F# won't compile if you try to capture a mutable variable in a closure. – gradbot Jul 19 '10 at 21:13
4

You are closing over the i variable.

Try this instead

for (int i = 0; i < 4; i++)
{
    int x = i;
    threadsArray[i] = new Thread(() => c1.k(x));
}
Winston Smith
  • 21,585
  • 10
  • 60
  • 75
0
Thread[] threadsArray = new Thread[4];
for (int i = 0; i < 4; i++)
{
    //better use ParameterizedThreadStart Delegate
    threadsArray[i] = new Thread(k);
}
for (int i = 0; i < 4; i++)
{
    //passing the value to the function
    threadsArray[i].Start(i);
}
for (int i = 0; i < 4; i++)
{
    threadsArray[i].Join();
}

//changing the input data type
void k(object i)
{
    while (true)
        Console.WriteLine((int)i);
}
KUL
  • 391
  • 2
  • 15