2010-06-21 38 views
5

我相信這工作,我已經與多個併發線程測試它(儘管沒有詳盡的競爭條件和死鎖):C#.NET 4.0 ConcurrentDictionary:鎖內的TryRemove?

public static System.Collections.Concurrent.ConcurrentDictionary<string, item> dict = 
     new System.Collections.Concurrent.ConcurrentDictionary<string, item>(); 
public static item dump; 

...

foreach (System.Collections.Generic.KeyValuePair<string, item> x in dict) 
{ 
    lock (x.Value) 
    { 
     if (x.Value.IsCompleted) 
     { 
      dict.TryRemove(x.Key, out dump); 
     } 
    } 
} 

這個問題是排序的這個問題的延續:

Can I remove items from a ConcurrentDictionary from within an enumeration loop of that dictionary?

而且這個問題:

Updating fields of values in a ConcurrentDictionary

在,我做兩個「冒險」演習:

  1. 刪除值從ConcurrentDictionary而在同一時間,通過它枚舉(這似乎是確定)。
  2. 鎖定ConcurrentDictionaryValue部分。必要的,因爲操縱值的字段不是線程安全的,只有操縱ConcurrentDictionary的值本身是線程安全的(上面的代碼是實際操縱值的字段的較大代碼塊的片段)。

回答

4

在迭代時從併發字典中刪除值是很好的。它可能會有一些性能影響(我不確定),但它應該起作用。

請注意,您並未鎖定ConcurrentDictionary的內部內容 - 您鎖定了與item對象關聯的顯示器。我個人不希望這樣做:要麼這些項目應該是線程安全的(無論如何操作它們)或(最好)不可變的,所以你可以從任何線程觀察它們而不鎖定。或者,當然,您可以讓您正在檢查線程安全的單個屬性。記錄你做的事情!

最後,您使用out dump似乎有點可疑。點只是爲了給TryRemove?如果是這樣,我會使用本地變量而不是靜態變量。

+1

感謝喬恩 是:轉儲意味着是一個毫無意義的包羅萬象。我會將它變成局部變量,因爲全局範圍public static是一個漏洞。 項目中的屬性:我將鎖定單個屬性而不是項目,如您所建議的。可能會有一種更優雅的方式來處理這個問題,但這些屬性會在一個線程中更改,在另一個線程中讀取,並在第三個項目級別刪除乾杯! – circletimessquare 2010-06-22 10:01:04

0

我最近發現的一個很好的選擇是關於如果是鍵/值匹配,這意味着您可以保證刪除一個對象(最好是值類型,而不是引用類型)更改。例如:

ConcurrentDictionary<string, int> cc = new ConcurrentDictionary<string, int>(); 

     cc.GetOrAdd("1", 1); 

現在假設以下兩行在併發/多線程場景中運行。

 cc.AddOrUpdate("1", 2, (a,b) => b + 1); 

     var removeSuccess = ((ICollection<KeyValuePair<string, int>>)cc).Remove(
    new KeyValuePair<string, int>("1", 1)); 

如果該值不會改變,你會刪除「1」成功,否則就會失敗,因爲你已經有相同的密鑰的新值。

對於下面的詳細信息檢查: http://thargy.com/2012/09/the-hidden-secret-of-the-concurrent-dictionary/http://blogs.msdn.com/b/pfxteam/archive/2011/04/02/10149222.aspx