2010-07-22 96 views
3

我有一個映射,每個鍵可以有多個關聯的值。我認爲ConcurrentDictionary可能會幫助我更容易地編寫該映射以用於多線程環境,但這些方法似乎是圍繞單個值構建的。我發現AddOrUpdate()讓我修改該值,如果它已經存在,但它不能保證該操作的原子性,所以它看起來毫無意義?有沒有人有解決這種情況的好策略?您可以使用ConcurrentDictionary進行一對多映射嗎?

對不起,我想我有點含糊。我想爲一個鍵有多個值,即有一個IList與鍵相關聯。但我希望能夠以安全的方式添加/刪除多值中的值。它看起來像AddOrUpdate +委託方法可能會導致事情迷路,如果在同一時間對它進行多次調用?

+0

你已經在標籤中有C#了。你也不需要把它放在標題中。此外,你的問題與C#4.0無關。 – 2010-07-22 18:57:05

回答

1

我認爲AddOrUpdate是原子的,但它看起來對代表來說不是原子的。抱歉!

,這可能有助於參考:http://blogs.msdn.com/b/pfxteam/archive/2009/11/06/9918363.aspx

+0

你錯了。該文檔指出,由於用戶代碼的不可預測性,對代理的調用不在鎖定下進行。 – evilfred 2010-07-22 18:04:53

+0

從您的鏈接:「關於集合上其他變異方法的原子(例如TryAdd/TryUpdate/TryRemove /等),不包括用戶提供的委託的執行。」 – evilfred 2010-07-22 18:05:44

+0

好吧,我明白你的意思了。我剔除了它並被曲解了。編輯帖子反映。 – mquander 2010-07-22 18:52:55

0

看起來既AddOrUpdateTryUpdate會工作。

編輯

我可能也錯了。如果是這樣,我認爲文檔沒有足夠清晰的說,所以我們來看看代碼。反射器的禮貌:

public TValue AddOrUpdate(TKey key, Func<TKey, TValue> addValueFactory, Func<TKey, TValue, TValue> updateValueFactory) 
{ 
    TValue local; 
    TValue local3; 
    if (key == null) 
    { 
     throw new ArgumentNullException("key"); 
    } 
    if (addValueFactory == null) 
    { 
     throw new ArgumentNullException("addValueFactory"); 
    } 
    if (updateValueFactory == null) 
    { 
     throw new ArgumentNullException("updateValueFactory"); 
    } 
    do 
    { 
     if (!this.TryGetValue(key, out local3)) 
     { 
      TValue local2; 
      local = addValueFactory(key); 
      if (!this.TryAddInternal(key, local, false, true, out local2)) 
      { 
       continue; 
      } 
      return local2; 
     } 
     local = updateValueFactory(key, local3); 
    } 
    while (!this.TryUpdate(key, local, local3)); 
    return local; 
} 

現在,如果更新了工廠現有列表,並返回一個額外成員一個新的,它確實看我,好像這將是原子。如果出現競爭狀況,失敗者將再次更新工廠。我錯了嗎?

+0

爲什麼TryAddInternal會返回與我們放入的東西不同的東西? – evilfred 2010-09-29 22:18:20

+0

最有可能TryAddInternal返回鍵的實際值,無論它是否返回false(即 - 無論是否添加第二個參數)。 – 2010-09-29 22:33:03

+1

如果我們不知道TryAddInternal是什麼,那麼閱讀該代碼就像閱讀茶葉一樣。 – evilfred 2010-09-30 00:05:10