2013-07-21 66 views
2

我在循環中啓動4個線程。每個線程獲取對數組元素的引用以寫入結果。在循環中傳遞數組元素的起始線程

但是,在我創建每個線程的線上,我得到了一個System.IndexOutOfRangeException。我很驚訝,指數「我」超出範圍。

這裏有一個例子:

void ThreadsStarter() 
{ 
    double[] data = new double[4]; 

    for(int i = 0; i < 4; i++) 
    { 
     Thread my_thread = new Thread(() => Work(data[i])); 
     my_thread.Start(); 
    } 
} 

void Work(double data) 
{ 
} 

爲什麼發生這種情況?

+2

您[[關閉循環變量]](http://blogs.msdn.com /b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx) – Blorgbeard

+0

我已經從您的示例/標題中刪除了'ref'作爲無關的問題 - 感覺自由編輯/回滾。注意'ref'通常很難使用/理解,特別是當您開始使用更靈活的集合時,例如'List '而不是'Array'。儘量避免使用'ref' - 即在這種情況下'Tuple.Create(data,i)'可能是一個選項(顯然是在lambda之前創建的,以避免您現在遇到的問題)。 –

+0

謝謝。現在我也知道那個建築的名字(閉合/ lambda)。我儘量避免參考。我會考慮使用元組,而這看起來更乾淨。這是一個很好的文章Blorgbeard。 – symbiont

回答

5

這是一個常見錯誤:當線程啓動時,我得到評估,這發生在循環結束後。做一個臨時工,分配給我,並使用溫度,而不是我在你的拉姆達解決問題:

void ThreadsStarter() 
{ 
    double[] data = new double[4]; 

    for(int i = 0; i < 4; i++) 
    { 
     var temp = i; 
     Thread my_thread = new Thread(() => Work(ref data[temp])); 
     my_thread.Start(); 
    } 
} 

void Work(ref double data) 
{ 
} 
+0

謝謝。這是有效的 – symbiont

+0

這是有效的,因爲當你重新創建一個臨時變量時,編譯器檢測到閉包在每個循環過程中「附加」到一個不同的變量,並且會生成一個「** new ** DisplayClass()」代碼封閉)在每個傳球內。如果沒有臨時變量,它將在所有循環中使用相同的DisplayClass(其中包含i變量的成員)。 (類似於c#5爲foreach循環生成的代碼 - 請參閱示例[here](http://aakinshin.net/en/blog/dotnet/closures/#the-foreach-loop))。 – BornToCode