问题描述
我在ASP.NET中有一个生产者-消费者方案.我设计了一个Producer
类,一个Consumer
类以及一个用于保存共享对象并负责Producer和Consumer之间通信的类,我们将其称为Mediator
.因为我在启动时(在父对象中)派生了执行路径,并且一个线程将调用Producer.Start()
,另一个线程将调用Consumer.Start()
,所以我需要将Mediator
的引用传递给Producer
和Consumer
(通过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()的线程问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!