线程切换和死锁预防问题

时间:2010-10-27 16:55:38

标签: c# multithreading deadlock

如果有两个线程作为生产者/消费者,最好有以下行来防止死锁。我知道实时锁,但是假设他们在调用Wait()方法之前做了很多工作:

// member variable
object _syncLock = new object();

void Wait()
{
   lock (_syncLock)
      {
         Monitor.Pulse(_syncLock);
         Monitor.Wait(_syncLock);
      }
}

这两个线程都不可能处于等待状态。

2 个答案:

答案 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无法使用。此集合应该非常高效,因为它对AddTake方法使用无锁策略。当然,就像我上面提到的那样,如果你真的想要配对变种,那么这个系列将无法满足你的要求,你将不得不使用Joe Duffy作为起点。

1 请记住在应用等待之前使用while循环而不是if检查。 Monitor.Wait只是等待锁定状态的更改而已,只需要重新检查等待条件。