如果有两个线程作为生产者/消费者,最好有以下行来防止死锁。我知道实时锁,但是假设他们在调用Wait()方法之前做了很多工作:
// member variable
object _syncLock = new object();
void Wait()
{
lock (_syncLock)
{
Monitor.Pulse(_syncLock);
Monitor.Wait(_syncLock);
}
}
这两个线程都不可能处于等待状态。
答案 0 :(得分:2)
这似乎过于复杂。只需首先正确处理锁定,避免出现问题。如果你只有两个线程,并且他们试图获得相同的单锁(正确),那么你不应该有死锁。死锁意味着此处还会发生其他事情。
话虽如此,如果您可以选择通过.NET 4(或.NET 3.5上的Rx扩展)使用TPL,您可能需要考虑使用BlockingCollection<T>
。它非常适合在生产者/消费者场景中使用,并以无锁方式工作。
答案 1 :(得分:1)
如果您打算创建生产者 - 消费者模式的配对变体,那么生成者Pulse
之前的序列为Wait
,而Wait
之前的序列为Pulse
消费者。您可以参考Joe Duffy's article on this中的图5。 Howerver,请记住,由于他的实现在Wait
方法中执行无条件Enqueue
,因此在生产者和消费者之间会发生类似乒乓的效果。在他的实现中,队列每个生产者只能有一个项目。所以,如果这是你的意图那么这是你的票。否则,您可以按原样对其进行调整,并将一些条件 1 应用于Wait
方法中的Enqueue
,使其行为更像真正的FIFO缓冲区。
然而,就像里德一样,我质疑为什么BlockingCollection
无法使用。此集合应该非常高效,因为它对Add
和Take
方法使用无锁策略。当然,就像我上面提到的那样,如果你真的想要配对变种,那么这个系列将无法满足你的要求,你将不得不使用Joe Duffy作为起点。
1 请记住在应用等待之前使用while
循环而不是if
检查。 Monitor.Wait
只是等待锁定状态的更改而已,只需要重新检查等待条件。