obj.Coll
在枚舉時發生了變化。如果它沒有被當前線程改變,它可能會被其他線程改變。如果集合被當前線程更改,基本上有兩種方法可以解決問題:您可以創建集合的副本並枚舉副本,或者可以推遲更改,直到枚舉集合。
但是,如果集合被另一個線程更改,則應該以線程安全的方式訪問集合(不僅在這裏,而且在任何地方)。
編輯爲基倫斯通:
我寫了一個短代碼,以證明List<T>.ToArray()
不是線程安全的。
var list = new List<int>();
Task.Factory.StartNew(() => {
for (int i = 0; i < 1000000; ++i) {
list.Clear();
// Add values from 1 to 9
for (int j = 1; j < 10; ++j) {
list.Add(j);
}
}
Console.WriteLine("Thread Exit: list.Add()");
});
Task.Factory.StartNew(() => {
for (int i = 0; i < 100; ++i) {
var array = list.ToArray();
if (array.Length > 0) {
Console.WriteLine("ToArray(): {0}", string.Join(", ", array));
}
}
Console.WriteLine("Thread Exit: list.ToArray()");
});
下面是輸出的片段。我想這證明了我的說法。該片段包含15行,其中9個包含錯誤的數據。
ToArray(): 1, 2, 3, 4
ToArray(): 1, 2, 3, 4, 5, 0, 0, 0, 0
ToArray(): 1, 2, 3, 4, 5, 6, 7, 0, 0
ToArray(): 0, 0, 0, 0, 0, 0, 0, 0, 0
ToArray(): 1, 2, 3, 4, 5, 0, 0, 0, 0
ToArray(): 0, 0, 0, 4, 5, 6, 7
ToArray(): 1, 2, 0, 0, 0, 0, 0, 0, 0
ToArray(): 1, 2, 3
ToArray(): 1, 0, 0, 0, 0, 0, 0, 0, 0
ToArray(): 0, 0, 0, 0, 0, 0, 0, 0
ToArray(): 1, 2
ToArray(): 1, 2, 3
ToArray(): 0, 0, 0, 0, 0, 0, 0, 0
ToArray(): 1, 2, 3, 4
ToArray(): 1, 2, 3, 4, 5, 6, 7, 8
將會有更多的變化,如果我們使用list.Insert(0, j)
代替list.Add(j)
。
「有時候」是發生了什麼事情的死亡泄露:另一個線程修改了收集。 – Jon 2011-03-31 09:24:14
[C#Collection可能的重複被修改;枚舉操作可能不會執行](http://stackoverflow.com/questions/2024179/c-sharp-collection-was-modified-enumeration-operation-may-not-execute) – nawfal 2013-06-05 17:52:25