2013-04-04 45 views
1

假設在C#中有多個線程正在訪問和更改的Dictionary<K, V>對象。您希望某些操作是線程安全的。C#中的數據結構的慣用,保證互斥?

所以你達到了一個互斥體。在C#中,使用一個互斥體的標準方法是:

lock (someSharedObject) 
{ 
    // Mutual exclusion zone here. 
    myDictionary.Add(1, "hello"); 
} 

的問題是,你在文檔僅僅依靠以保持未來的程序員直接訪問字典,繞過互斥:

myDictionary.Add(1, "hello"); 

我想讓編譯器阻止未來的程序員使用不受保護的字典。

我看到兩個普通可能性:

  1. 創建一個酷似詞典(比如,LockedDictionary),這保證了它的成員方法鎖定,但其他各方面的行爲像一個字典。
  2. 創建守衛訪問Dictionary一類,因此無需通過保護會調用者不能達到Dictionary

這些履行現在沒有人可以不受保護,至少意外地使用字典的願望屬性。我想討論兩者的利弊,然後要求你同意或不同意我的看法,並提出我可能忽略的解決方案。

LockedDictionary的好處是,它直觀的爲別人着想。它還允許對哪些方法需要鎖定以及程度進行細粒度控制。缺點是它不完全是Dictionary,所以你不能將這個對象傳遞給一個預期會收到Dictionary的函數。 (雖然你可以通過實現IDictionary接近。)

移動到#2。保護類的好處是,你可以實現IDisposable和使用它像這樣:

class DictionaryFortress { 
    Dictionary<K, V> realDict; 
    Object lockobject; 
    void Lock() { 
     Monitor.Enter(lockobject); 
     return DictionaryGuard(lockobject, realDict); 
    } 
} 

class DictionaryGuard : IDisposable { 
    public Dictionary<K, V> Dict { 
     get { return realDict; } 
    } 
    public void Dispose() { 
     Monitor.Exit(lockobject); 
    } 
} 

// in some class 
DictionaryFortress dict = new DictionaryFortress(); // early on 

// in a function, when we need to access dictionary contents... 
using (DictionaryGuard guard = dict.Lock()) { 
    Dictionary<K, V> actualDict = guard.Dict; 
    // now you can pass actualDict anywhere; no one has to know that it's locked 
} 

的好處,當然是我們必須訪問原始的字典,所以我們沒有在如何約束我們可以使用它,我們可以通過它。缺點是使用它的開銷更大。用戶還可以在可用時保存對guard.Dict的引用,然後在丟棄DictionaryGuard後使用它。

我傾向#2。我有沒有錯過任何優點和缺點?有沒有更好的方法來保護對我的字典的訪問,同時最大限度地減少濫用的風險?同樣,我的要求是一個健忘或粗心的程序員不能跳過鎖定階段。我的願望是它的習慣,方便和靈活。

+7

你考慮['ConcurrentDictionary 中'](http://msdn.microsoft。COM/EN-US /庫/ dd287191.aspx)? – jrummell 2013-04-04 20:10:21

+1

或其他線程安全集合的ConcurrentBag,ConcurrentQueue和ConcurrentStack。沒有重新發明輪子... – Pete 2013-04-04 20:11:17

+1

謝謝。雖然我知道我確實在重新發明輪子,但我忘記了這些的存在。你會發布這個建議的答案嗎? – Philip 2013-04-04 20:18:49

回答