2016-06-10 50 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

酷 - 我已经使用了它几次,结果很好。 –