2014-02-16 33 views
2

爲了避免著名的錯誤:我應該使用鎖或ToList()

Collection was modified; enumeration operation may not execute

迭代的 IEnumerator

,我應該只使用ToList()作爲this questions建議,或者我應該使用lock更新列表時?

我的問題是,ToList()只是每次都創建一個新列表,而lock只會在更新列表時在某些點上有小的延遲。

那麼,我應該使用ToList()還是lock

+2

鎖不起作用的情況下,列表在同一個線程上更改並且ToList不能使用列表線程安全 – Steven

+0

這是在WCF服務中,我最好檢查線程。我總是對線程和WCF感到困惑。 –

+0

一般而言,Web服務可能意味着您的代碼在理論上*在一個仲裁線程上被訪問*。在我的Web服務中,我使用'ReadWriterLockSlim'來確保集合讀取處於讀取鎖定狀態,並且在更新時顯然是寫入鎖定。 –

回答

3

您看到的錯誤告訴您,您正在嘗試在枚舉它時修改集合。 lock關鍵字適用於多線程情況,它確保只有一個線程處於關鍵部分。它與「鎖定」收集無關,因此您可以枚舉它並修改它。

您通常看到的錯誤與代碼中出現一樣,如果你有一個線程枚舉集,而其他線程添加或刪除收集以下

foreach(var item in items) 
{ 
    //Inside this loop now you are enumerating collection 
    //This means you can't add or delete anything from items 
    items.Add(newItem); //This will produce the error you are seeing 
} 

也可能會出現此錯誤。所以如果你知道你有多線程的情況,那麼你可以使用lock,雖然它有點棘手,可能會影響你的併發性能,甚至會導致競爭狀態。對於多線程情況,僅使用ToList可能不夠,因爲在調用ToList時需要確保只有一個線程可以訪問集合。因此,您可能需要使用ToList以及鎖定,根據您的情況,它可能會更簡單。要查看如何在枚舉中進行線程安全修改的示例,請參閱此答案:Making a "modify-while-enumerating" collection thread-safe

如果你知道你沒有多個線程,那麼ToList可能是你唯一的選擇,你根本不需要lock。我還建議確定在枚舉時是否確實需要修改集合。在許多情況下(但不是全部),您可以採取不同的設計,以避免它首先出現。

+0

枚舉時我不修改列表,它是一個小型緩存系統,有時在閱讀列表時其他函數正在調用添加方法... –

+0

這個其他函數是否在單獨的線程上運行?如果是這樣,請按照答案中的鏈接。否則,只需使用ToList,如答案中所述。 – ShitalShah