2010-08-05 69 views
2

所以我有一個方法,獲取列表字典<myObj>,然後循環通過字典的鍵,並將每個列表<myObj>傳遞到一個單獨的線程。線程執行期間C#線程參數發生變化 - 爲什麼?

下面是一些代碼/僞代碼:

public static void ProcessEntries() { 

    Dictionary<string, List<myObj>> myDictionary = GetDictionary(); 

    foreach(string key in myDictionary.keys) 
    { 

     List<myObj> myList = myDictionary[key]; 

     Thread myThread = new System.Threading.Thread(new System.Threading.ThreadStart(delegate() { 

      ProcessList(myList); 

     }  
    } 
} 

public static void ProcessList(List<myObj> myList) { 

    // Process entries 
    // read-only operations on myList 

} 

的問題是,ProcessList中的執行期間myList中參數簡單地改變。

我踢過線程之前已經遍歷列表,然後馬上在線程內部,我發現結果是不同的。

我已經解決了問題(我想!),通過使字典變量全局。使用[ThreadStatic]屬性位於可能修復列表的旁邊。

我真的很想知道爲什麼myList對象在ProcessList()內部發生變化,這大概是在ProcessEntries()中重新分配myList對象的時候?這些不是兩個不同的列表嗎?如果所有參數傳遞都是默認值,那麼爲什麼ProcessList()函數沒有myList的本地副本? (是嗎?)

有沒有辦法指定你想傳遞一個參數給一個線程,而不是在執行過程中被父線程或其他線程改變了? (這將類似於全局變量的[ThreadSafe]屬性)

+1

你確定你的代碼/ psuedocode是正確和完整的嗎?從我所看到的,雖然你對發生的事情的假設是錯誤的,但它看起來像代碼應該工作得很好。 – 2010-08-05 16:57:19

回答

0

在這種情況下,您正在傳遞參考的值,所以如果您在某處修改它,它將會每隔一定時間會有所不同。

2

我懷疑你的僞代碼實際上並不是你的真實代碼的準確反映。我懷疑你的真正代碼如下所示:

foreach(var pair in myDictionary) 
{ 
    Thread myThread = new Thread(delegate() { 
     ProcessList(pair.Value); 
    }); 
    myThread.Start(); 
} 

如果是這樣的話,問題是,pair變量被抓獲 - 所以你的線程開始的時候,它可能是指不同的密鑰/值對。

解決它的方法是使代碼更精確喜歡你的僞代碼:

foreach(var pair in myDictionary) 
{ 
    // You'll get a new list variable on each iteration 
    var list = pair.Value; 
    Thread myThread = new Thread(delegate() { 
     ProcessList(list); 
    }); 
    myThread.Start(); 
} 

更多信息請參見Eric Lippert's blog post on this

如果這沒有什麼問題,請給出一個真實的例子而不是僞代碼。 A short but complete example demonstrating the problem將是理想的。

1

還要確保其他線程不會影響您嘗試使用的線程。一定要使用鎖和顯示器...幾個星期前有一些問題..