2010-07-19 65 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)); 
}