2010-07-19 22 views
9

tôi có mã này:mảng của bài 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(); 
     } 

chức năng k là thế này:

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

vì một lý do chỉ là chủ đề cuối cùng đang chạy và in 4.444.444 .... tại sao không phải tất cả các chủ đề đều chạy?

+9

này có phải là biến thể kỳ quặc nhất của việc đóng cửa-over-the-loop-biến câu hỏi tiêu chuẩn mà tôi từng thấy. –

+0

Điều này thậm chí còn tương tự hơn: http://stackoverflow.com/questions/1930133/c-closures-why-is-the-loopvariable-captured-by-reference –

+0

Liên quan: "Đóng trên biến vòng lặp được coi là có hại" bởi Eric Lippert. http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx –

Trả lời

22

Tất cả các chủ đề đang in cùng một biến.

Biểu thức lambda của bạn (() => c1.k(i)) chụp biến số i bằng cách tham chiếu.
Do đó, khi biểu thức lambda chạy sau i++, nó sẽ nhận giá trị mới là i.

Để sửa lỗi này, bạn cần phải khai báo một biến riêng biệt bên trong vòng lặp để mỗi lambda được biến riêng của mình, như thế này:

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

+1 cho câu trả lời này. Về cơ bản nó giống với Winston, nhưng lời giải thích thì chi tiết hơn. – schnaader

+0

Trên một lưu ý phụ: một số ngôn ngữ như F # sẽ không biên dịch nếu bạn cố gắng nắm bắt một biến có thể thay đổi trong một đóng. – gradbot

4

Bạn đang đóng trên các biến i.

Hãy thử điều này thay vì

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