2010-07-19 11 views
9

mam ten kod:szereg wątków 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(); 
     } 

funkcja k jest taka:

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

z jakiegoś powodu po prostu ostatni wątek jest uruchomiony i drukowanie 4444444 .... dlaczego czy wszystkie wątki nie działają?

+9

To musi być najbardziej dziwak wariant standardowy zamykanie-over-the-loop-zmienna pytanie, jaki kiedykolwiek widziałem. –

+0

Ten jest jeszcze bardziej podobny: http://stackoverflow.com/questions/1930133/c-closures-why-is-the-loopvariable-captured-by-reference –

+0

Powiązane: "Zamknięcie zmiennej pętli za szkodliwe" przez Eric Lippert. http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx –

Odpowiedz

22

Wszystkie wątki drukują tę samą zmienną.

Twoje wyrażenie lambda (() => c1.k(i)) przechwytuje zmienną i przez odniesienie.
Dlatego też, gdy wyrażenie lambda działa po i++, odbiera nową wartość i.

Aby rozwiązać ten problem, trzeba zadeklarować oddzielną zmienną wewnątrz pętli tak, że każdy ma własne lambda zmienna, tak:

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

+1 dla tej odpowiedzi. Jest w zasadzie taki sam jak Winstona, ale wyjaśnienie jest bardziej szczegółowe. – schnaader

+0

Na marginesie: niektóre języki, takie jak F #, nie będą kompilowane, jeśli spróbujesz uchwycić zmienną zmienną w zamknięciu. – gradbot

4

Jesteś zamykania nad zmiennej i.

Spróbuj zamiast

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