2014-10-01 52 views
1

考慮下面的函數,它迭代通用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中。

這是一個明智的方式來修改線程安全的方式收集?

+1

如果你的'ID'是唯一的,我會說'ConcurrentDictionary'更合適。不,你的第二種方法不是線程安全的,因爲你沒有使用任何鎖,並且正在取物品,創建一個臨時包等等,如果它們同時發生會造成問題。 – Maarten 2014-10-01 09:55:07

+0

@Maarten謝謝 - 根據項目中使用的類別,ID未必是唯一的,因爲未保存的條目的ID爲0。另外,我認爲Concurrent命名空間使用了它自己的內部鎖定方法。我的函數也使用我認爲是從ConcurrentBag:TryTake()中刪除項目的線程安全方法? – Panjo 2014-10-01 10:14:01

+1

如果你想要某個被稱爲*線程安全*的東西,那麼**作爲一個整體**的操作必須是線程安全的,並且使用線程安全的方法移除一個項目是不夠的。 – Maarten 2014-10-01 10:34:10

回答

-1

您的併發版本UpdateList不是線程安全的,因爲它引入了race condition

您的第一版UpdateList與多線程情況下的第二版不相同。你明白爲什麼?如果你啓動兩個線程執行UpdateList一個與idToFind_1和另一個與idToFind_2工作在相同的ConcurrentBag<T> Items。然後,第一個線程可能會取出第二個需要更新的項目。因此,具有idToFind_2的項目很可能會錯過更新,反之亦然。在這裏,我們有競賽條件:如果線程1將該項目及時返回,它將得到更新否則它不會。

此外,你仍然要處理,你突變所從多個線程訪問的項目的事實,因爲它是不是安全(Servy的評論)。

由於實施在某種程度上效率低下。您是否考慮過使用另一個更合適的數據結構,並且可能會利用lock來關注同步,其他任何代碼塊都使用該代碼塊來提供對數據結構的相同實例的獨佔訪問。

此外,由於tempItems位於UpdateList的本地,因此您不需要線程安全的集合,因爲沒有同步。所以一個簡單的List<T>就足夠了。

您不需要參數ref關鍵字,請參閱When to use ref and when it is not necessary in C#

+1

OP的代碼*不安全。只有在訪問這些數據的其他代碼塊都鎖定在同一實例上時,'lock'纔有用。如果沒有'ref'關鍵字,對象將不會被引用傳遞。它會通過價值傳遞,但是這個價值會成爲一個參考。這是一個非常重要的區別。 – Servy 2014-10-01 16:49:42