[英]How to create a Lockfree collection of collection
我需要創建一個集合集合。 多個線程調用該集合以添加項和查找項。 添加后,項目將不會被刪除。 目前,在添加元素時我需要鎖定整個集合。 有沒有辦法讓它無鎖。 或者,我可以使用更好的數據結構或模式嗎? 這是我的代碼的簡化版本:
readonly ConcurrentDictionary<string, ConcurrentDictionary<int, int>> dict = new ConcurrentDictionary<string, ConcurrentDictionary<int, int>>();
void AddUpdateItem(string s, int k, int v)
{
ConcurrentDictionary<int, int> subDict;
if (dict.TryGetValue(s, out subDict))
{
subDict[k] = v;
}
else
{
lock (dict)
{
if (dict.TryGetValue(s, out subDict))
{
subDict[k] = v;
}
else
{
subDict = new ConcurrentDictionary<int, int>();
subDict[k] = v;
dict[s] = subDict;
}
}
}
}
您可以通過使用不變性來使哈希表無鎖,但如果存在爭用則不太可能有效。 基本上,您需要一個可以原子交換的字典內容類。 您構建了當前內容的副本,並進行了一次更改,然后使用比較和交換原語將其與現有版本進行交換。 如果比較和交換失敗,請從復制步驟開始。
您可以原子地交換一個哈希桶,這會使爭用更不常見,並重試更便宜。 ( ConcurrentDictionary
已經使用了這種優化,以減少鎖爭用)但是增加桶的數量仍然需要上面概述的方法。
看看Eric Lippert的博客,其中涵蓋了不可變數據結構。 他有一個很好的二叉樹示例 ,它應該向您展示制作無鎖散列表所需的技術。
方法ConcurrentDictionary.GetOrAdd
是線程安全的(雖然不是原子的)。 它保證返回的對象對於所有線程都是相同的。 您的代碼可以重寫為:
void AddUpdateItem(string s, int k, int v)
{
var subDict = dict.GetOrAdd(s, _ => new ConcurrentDictionary<int, int>());
subDict[k] = v;
}
您是否在代碼中使用任務或線程? 無論如何, ConcurrentDictionary
被設計為線程安全的。 添加或刪除元素時不需要使用鎖。 從MSDN鏈接如何:在ConcurrentDictionary中添加和刪除項目解釋了如何使用它。
如果您推測性地創建子字典,則有一個更簡單的解決方案:
readonly ConcurrentDictionary<string, ConcurrentDictionary<int, int>> dict = new ConcurrentDictionary<string, ConcurrentDictionary<int, int>>();
void AddUpdateItem( string s, int k, int v )
{
ConcurrentDictionary<int, int> subDict;
while ( true )
{
if ( dict.TryGetValue( s, out subDict ) )
{
subDict[ k ] = v;
break;
}
// speculatively create new sub-dictionary
subDict = new ConcurrentDictionary<int, int>();
subDict[ k ] = v;
// this can only succeed for one thread
if ( dict.TryAdd( s, subDict ) ) break;
}
}
在你實現無鎖集合之前,先看看ReadWriteLock來解決你的問題。 如果沒有(例如因為你有很大的寫入爭用),那么實際上並沒有一種通用的方法。
我過去使用的一種技術是使用一個線程專用線程來管理集合,並使用Interlocked.Exchange
將新對象封送到該線程和一個不可變集合。 使用這種方法,您的編寫器線程將在一個單獨的列表中進行管理,無論何時創建或銷毀編寫器,您都需要鎖定它,因此只有在這是一個罕見的事件時才有效。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.