2010-07-19 39 views
9

我有这样的代码:阵列线程C#

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(); 
     } 

功能k是这样的:

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

出于某种原因刚刚过去的线程运行并打印4444444 .... 为什么并不是所有线程都在运行?

+9

这必须是标准的闭合过度的循环变量是我见过的问题的最古怪的变种。 – 2010-07-19 20:51:36

+0

这一个更类似:http://stackoverflow.com/questions/1930133/c-closures-why-is-the-loopvariable-captured-by-reference – 2010-07-19 21:06:58

+0

相关:“关闭循环变量被认为是有害的”由Eric Lippert。 http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx – 2010-07-20 07:56:51

回答

22

所有线程都打印相同的变量。

您的lambda表达式(() => c1.k(i))通过引用捕获i变量。
因此,当lambda表达式在i++之后运行时,它将拾取新值i

要解决这个问题,你需要声明循环中一个独立的变量,使每个拉姆达都有自己的变量,就像这样:

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

+1。这与温斯顿的基本相同,但解释更加详细。 – schnaader 2010-07-19 20:53:42

+0

附注:如果您尝试在闭包中捕获可变变量,则某些类似F#的语言将无法编译。 – gradbot 2010-07-19 21:13:59

4

你关闭在我的变量。

试试这个

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