2016-06-10 68 views
0

我正在寫性能關鍵代碼,因此想要最大限度地減少對lock(){ ... }的調用。
關鍵部分是一個字典:C#條件鎖

private static readonly Dictionary<string, System.Messaging.MessageQueue> _messageQueues; 

讀取,並在同一時間從/到字典添加時,則有可能是損壞的數據。這就是爲什麼我不想同時允許這兩個操作。

SOLUTION 1

lock (_lock) { 
    _messageQueues.Add(queueName, result); 
} 

和另一種方法:

lock(_lock){ 
    if (_messageQueues.TryGetValue(queueName, out result)) { 
     return result; 
    } 
} 

但我不喜歡這樣的解決方案,因爲現在只有一個線程可以同時讀取。
如果正在進行書寫,我想允許多個讀者或者沒有讀者。

解決方案2
添加一個布爾字段:

private static volatile bool _currentlyModifying; 

寫入字典這樣的:

try { 
    _currentlyModifying = true; 
    lock (_lock) { 
     _messageQueues.Add(queueName, result); 
    } 
} 
finally { 
    _currentlyModifying = false; 
} 

和閱讀這樣的:

if (_currentlyModifying) { 
    lock (_lock) { 
     if (_messageQueues.TryGetValue(queueName, out result)) { 
     return result; 
     } 
    } 
} else { 
    //Here is the new problem 
    if (_messageQueues.TryGetValue(queueName, out result)) { 
     return result; 
    } 
} 

問題
這將工作得很好,但有一個競爭條件:
一個線程可以開始寫後,另一個線程已開始閱讀。
有沒有辦法解決這個問題?

+3

爲什麼不使用'ConcurrentDictionary '而不是? –

+0

查看.Net的ConcurrentDictionary類可能會有所幫助。只是不知道它如何處理哪些線程可以讀取,但我認爲他們有一個很好的解決方案。 –

+0

解決方案2(用於* general *用法)的另一個問題是,是否有多個寫入者嘗試訪問該鎖。如果他們都同時到達'lock()',他們中的一個將進入,進行更改,釋放鎖(第二個寫入者現在可以獲得鎖),* unsets *'_currentlyModifying',而第二個寫入者仍然在鎖裏面。 –

回答

2

正如評論中所述,您可以使用ConcurrentDictionary。如果你沒有這個功能,那麼你可以將你的代碼分割到讀者和編寫者(比如小規模的CQRS),並使用ReaderWriterLockSlim類來優化性能。

+0

真棒我已經有這個問題幾次了。很棒的是有一個開箱即用的解決方案:) –

+0

酷 - 我已經使用了它幾次,結果很好。 –