本文介绍了Monitor.Wait()和Monitor.Pulse()的线程问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在ASP.NET中有一个生产者-消费者方案.我设计了一个Producer类,一个Consumer类以及一个用于保存共享对象并负责Producer和Consumer之间通信的类,我们将其称为Mediator.因为我在启动时(在父对象中)派生了执行路径,并且一个线程将调用Producer.Start(),另一个线程将调用Consumer.Start(),所以我需要将Mediator的引用传递给ProducerConsumer (通过Constructor). Mediator是一个智能类,它将优化许多事情,例如内部队列的长度,但现在将其视为循环阻塞队列. Producer排队新对象到Mediator,直到队列已满,然后Producer将阻塞. Consumer 使Mediator中出队对象,直到队列中没有任何对象为止.为了在线程之间发出信号,我在Mediator类中实现了两个方法:Wait()Pulse().代码是这样的:

Class Mediator
{
  private object _locker = new object();

  public void Wait()
  {
    lock(_locker)
      Monitor.Wait(_locker);
  }

  public void Pulse()
  {
    lock(_locker)
      Monitor.Pulse(_locker);
  }
}

// This way threads are signaling:

Class Consumer
{
  object x;
  if (Mediator.TryDequeue(out x))
    // Do something
  else
    Mediator.Wait();
}

在内部调解器中,每当入队出队时,我都会使用this.Pulse(),这样会发出等待线程的信号并继续其工作.

但是我遇到死锁,因为我从未使用过这种设计来发信号通知线程,所以我不确定设计是否有问题,或者我在其他地方做错了吗?

谢谢

解决方案

设计没有问题.

当您使用Monitor.Wait()Monitor.Pulse()时,如果您不知道哪个线程将首先执行该操作(生产者或使用者),则会出现问题.在这种情况下,使用AutoResetEvent可解决问题.当消费者到达应该使用生产者产生的数据的区域时,请考虑一下消费者.也许它在生产者将其脉冲之前到达那里,然后一切正常,但是如果消费者在生产者发出信号之后到达那里,该怎么办.是的,您会遇到死锁,因为生产者已经为该部分调用了Monitor.Pulse(),因此不再重复.使用AutoResetEvent,您可以确保消费者在那儿等待生产者发出的信号,如果生产者在消费者到达该部分之前已经发出信号,则大门是打开的,消费者将继续.

可以在Mediator中使用Monitor.Wait()Monitor.Pulse()来发出等待线程的信号.

I have a producer-consumer scenario in ASP.NET. I designed a Producer class, a Consumer class and a class for holding the shared objects and responsible for communication between Producer and Consumer, lets call it Mediator. Because I fork the execution path at start-up (in parent object) and one thread would call Producer.Start() and another thread calls Consumer.Start(), I need to pass a reference of Mediator to both Producer and Consumer (via Constructor). Mediator is a smart class which will optimize many things like length of it's inner queue but for now consider it as a circular blocking queue. Producer would enqueues new objects to Mediator until the queue gets full and then Producer would block. Consumer dequeues objects from Mediator until there's nothing in the queue. For signaling between threads, I implemented two methods in Mediator class: Wait() and Pulse(). The code is something like this:

Class Mediator
{
  private object _locker = new object();

  public void Wait()
  {
    lock(_locker)
      Monitor.Wait(_locker);
  }

  public void Pulse()
  {
    lock(_locker)
      Monitor.Pulse(_locker);
  }
}

// This way threads are signaling:

Class Consumer
{
  object x;
  if (Mediator.TryDequeue(out x))
    // Do something
  else
    Mediator.Wait();
}

Inside Mediator I use this.Pulse() every time something is Enqueued or Dequeued so waiting threads would be signaled and continue their work.

But I encounter deadlocks and because I have never used this kind of design for signaling threads, I'm not sure if something is wrong with the design or I'm doing something wrong elsewhere ?

Thanks

解决方案

Nothing is wrong with design.

Problem raises when you use Monitor.Wait() and Monitor.Pulse() when you don't know which thread is going to do it's job first (producer or consumer). In that case using an AutoResetEvent resolves the problem. Think of consumer when it reaches the section where it should consume the data produced by producer. Maybe it reaches there before producer pulse it, then everything is OK but what if consumer reaches there after producer has signaled. Yes, then you encounter a deadlock because producer already called Monitor.Pulse() for that section and would not repeat it.Using AutoResetEvent you sure consumer waits there for signal from producer and if producer already has signaled before consumer even reaches the section, the gate is open and consumer would continue.

It's OK to use Monitor.Wait() and Monitor.Pulse() inside Mediator for signaling waiting threads.

这篇关于Monitor.Wait()和Monitor.Pulse()的线程问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-17 03:38