考慮下面的函數,它迭代通用List<T>
:項目,並改變匹配的項目,如果發現:用於修改ConcurrentBag中項目的可接受方法?
void UpdateList(ref List<clsMyClass> Items, int idToFind) {
foreach(var Item in Items) {
if (Item.ID == idToFind)
{
// modify the item
Item.SomeIntCounter++;
return;
}
}
}
現在,如果我想要做同樣的事情,但使用一個線程安全的這個時候ConcurrentBag<T>
,這是一個可以接受的方法?...
void UpdateList(ref ConcurrentBag<clsMyClass> Items, int idToFind) {
clsMyClass Item;
bool found = false;
ConcurrentBag<clsMyClass> tempItems = new ConcurrentBag<clsMyClass>();
while(Items.Count > 0) {
if (Items.TryTake(out Item))
{
if (Item.ID == idToFind)
{
//modify the item
Item.SomeIntCounter++;
found = true;
}
tempItems.Add(Item);
if (found) break;
}
}
foreach(var tempItem in tempItems) Items.Add(tempItem);
}
這裏的想法是,每個項目從ConcurrentBag刪除並添加到一個臨時直到匹配的項目被發現,改變,在此之後所有拆下的項目被重新添加到ConcurrentBag中。
這是一個明智的方式來修改線程安全的方式收集?
如果你的'ID'是唯一的,我會說'ConcurrentDictionary'更合適。不,你的第二種方法不是線程安全的,因爲你沒有使用任何鎖,並且正在取物品,創建一個臨時包等等,如果它們同時發生會造成問題。 – Maarten 2014-10-01 09:55:07
@Maarten謝謝 - 根據項目中使用的類別,ID未必是唯一的,因爲未保存的條目的ID爲0。另外,我認爲Concurrent命名空間使用了它自己的內部鎖定方法。我的函數也使用我認爲是從ConcurrentBag:TryTake()中刪除項目的線程安全方法? – Panjo 2014-10-01 10:14:01
如果你想要某個被稱爲*線程安全*的東西,那麼**作爲一個整體**的操作必須是線程安全的,並且使用線程安全的方法移除一個項目是不夠的。 – Maarten 2014-10-01 10:34:10