2013-07-10 91 views
3

我正在使用管理線程池來運行操作的類。它最初被編碼到採取行動(不帶參數)和我打電話這樣說:多線程和lambda變量範圍

void LoadTasks() 
{ 
    string param; 

    // some code loops and changes param 
    { 
     threadPool.EnqueueTask(() => SomeMethod(param)); 
    } 
} 

由於線程運行一些被罰款,但偶爾帕拉姆變量是不是我所期待...它是一個「更新」的價值,而不是我打算髮送給該方法的東西。

將線程池更改爲接受Action<Object>並調用時沒有使用lambda - 像threadPool.EnqueueTask(SomeMethod, param) - 解決了我的問題。

我看到了很多關於C#lambda關於線程安全性的問題。例如,lambdas an accepted answer不太可能比您預期的線程安全。我正在尋找有關lambda/closures/scoping的其他問題和答案,令人困惑。所以我正在尋找一個lambda表達式和變量範圍的解釋,理想情況下與我的例子中的問題有關。

+1

這個問題和我的答案可能對你有幫助:http://stackoverflow.com/questions/8898925/is-there-a-reason-for-cs-reuse-of-the-variable-in-a -foreach –

回答

2

所以問題是,你正在關閉你不想要的變量。在大多數情況下,簡單的修復方法是創建一個新的局部變量,複製一次您關閉的變量,然後關閉而不是

所以不是:

for(int i = 0; i < number; i++) 
{ 
    threadPool.EnqueueTask(() => SomeMethod(someList[i])); 
} 

你可以這樣做:

for(int i = 0; i < number; i++) 
{ 
    int copy = i; 
    threadPool.EnqueueTask(() => SomeMethod(someList[copy])); 
} 

現在每個拉姆達關閉了它自己的變量,而不是關閉在同一個變量所有的人。

+0

如果我錯了,請糾正我的錯誤:我明白,lambda函數中的變量在函數被調用時被評估。所以在我的情況下,'param'字符串仍然在一個線程的範圍內,當lambda在另一個線程中執行時,它將使用以及'param'在那個時候的任何值。因此,爲了迴應你的陳述「現在每個lambda正在關閉它自己的變量」,我問什麼讓一個lambda「擁有」變量?如果它不在其他地方,它是否擁有? – jltrem

+0

@jltrem lambda不會「擁有」它,這僅僅是兩個lambda是否關閉同一個變量,或者是否有兩個變量,以至於每個變量只能關閉一個lambda。在某些情況下,對於多個lambda來說,關閉一個變量是可取的,您已經指出,在這種情況下,您不需要這樣做,所以避免它的方法是創建新變量。 – Servy

+0

真的我的困惑並不瞭解_closure_的概念。我沒有完全理解1)lambda表達式捕獲變量和2)捕獲變量之間的連接,直到代碼被調用才被評估。它只是沒有沉入。菜鳥的錯誤。感謝您讓我朝着正確的方向前進。 – jltrem