C# PulseAll 不会唤醒休眠线程
我遇到一种情况,有时休眠线程不会被 Monitor.PulseAll(object lock)
命令唤醒。这种现象不是确定性的。一般来说,它可以工作,但有时在调试过程中,睡眠线程无法唤醒,我的队列不断填满。
如果队列为空,工作线程将进入睡眠状态:
private void Dequeue()
{
try
{
while (true)
{
T item;
lock (_lock)
{
if (_queue.Count == 0)
{
Monitor.Wait(_lock); //thread stays asleep here. why?
}
item = _queue.Dequeue(); //break point [1]
}
}
}
catch (ThreadAbortException ex)
{
_logger.Error(ex)
}
}
添加时,队列至少有一项,并且锁对象上的 PulseAll 应该唤醒线程。
public void Add(T item)
{
Validate.NotNull(item, "item must not be null");
lock (_lock)
{
_queue.Enqueue(item);
_queueInfoAdministrator.IncrementCount();
Monitor.PulseAll(_lock);
}
}
有没有其他人有类似的经历或者可以为我指出正确的方向,为什么会发生这种情况(有时)?
编辑2011年4月8日: 更多信息 - 只有一个消费者线程。所以理论上一个Pulse
就足够了。一旦达到消费者线程保持睡眠状态的状态,我就可以继续将项目入队并随后调用 PulseAll,而无法唤醒睡眠线程。我放置了一个断点[1],在所描述的情况下它永远不会被击中。因此,我相信这不是 Pulse/Monitor 的 MSDN 页面中描述的死锁问题。
I have a situation, where sometimes sleeping threads are not woken on a Monitor.PulseAll(object lock)
command. The phenomenon is not deterministic. In general it works, but sometimes during debbuging, the sleeping threads fail to wake and my queue keeps filling up.
The working thread is put to sleep, if the queue is empty:
private void Dequeue()
{
try
{
while (true)
{
T item;
lock (_lock)
{
if (_queue.Count == 0)
{
Monitor.Wait(_lock); //thread stays asleep here. why?
}
item = _queue.Dequeue(); //break point [1]
}
}
}
catch (ThreadAbortException ex)
{
_logger.Error(ex)
}
}
Upon Add the queue has at least one item and PulseAll
on the lock-object should wake the threads.
public void Add(T item)
{
Validate.NotNull(item, "item must not be null");
lock (_lock)
{
_queue.Enqueue(item);
_queueInfoAdministrator.IncrementCount();
Monitor.PulseAll(_lock);
}
}
Does anyone else have similar experiences or could point me in the right direction, as to why this happens (sometimes)?
EDIT 2011.04.08:
Further information - there is only one consumer thread. So theoretically a Pulse
would suffice. Once the state has been reached, where the consumer thread stays sleeping, I can continue to enqueue items and subsequently call PulseAll
without being able to wake the sleeping thread. I placed a break point [1], which never gets hit in the described situation. Therefore I believe it is not a deadlock problem as described in the MSDN pages to Pulse/Monitor.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您确定线程处于休眠状态吗?您的代码调用了
_queue.Dequeue
,如果队列中没有项目,它将引发异常。因此,如果两个线程正在等待锁,则当Add
方法将一个项目入队并调用PulseAll
时,两个线程都将被释放。第一个线程将调用Dequeue
并获取队列中唯一的项目。下一个线程将调用Dequeue
并抛出异常。如果您捕获并吞掉了该异常,您将永远不会看到它。由于异常已经逃脱了 while 循环,因此线程终止并且队列将开始填充。另外,虽然我怀疑这在您的情况下是一个问题,但请参阅 http://msdn.microsoft.com/en-us/library/system.threading.monitor.pulse.aspx,其中讨论了使用
Pulse
和潜在的死锁脉冲全部。
Are you sure that the threads are asleep? Your code has a call to
_queue.Dequeue
, which is going to throw an exception if there are no items in the queue. So if two threads are waiting on the lock, when theAdd
method enqueues an item and callsPulseAll
, both threads will be released. The first thread will callDequeue
and get the only item in the queue. The next thread will callDequeue
and throw an exception. If you're catching and swallowing that exception, you'll never see it. And since the exception has escaped thewhile
loop, the thread terminates and the queue will begin to fill.Also, although I doubt this is an issue in your case, see http://msdn.microsoft.com/en-us/library/system.threading.monitor.pulse.aspx, where it talks about potential deadlock using
Pulse
andPulseAll
.当 Dequeue 函数没有等待时,您是否会感到脉冲?如果是这样,直到下一个脉冲才会触发等待。
请参阅关于 Pulse 的重要说明
Could it be you are pulsing when the Dequeue function is not waiting? If so the wait will not be triggered until the next pulse.
See the important note on Pulse
Wait
调用应始终在等待条件的While
循环中使用。原始代码不使用
While
循环,而是使用If语句。<代码>
锁(_lock)
{
// 错误: if (_queue.Count == 0)
while (_queue.Count == 0)
{
监视器.Wait(_lock); //线程在这里保持休眠状态。为什么?
}
有关详细说明,请参阅本文第 4 部分的“使用等待和脉冲发送信号”部分:C# 中的线程
the
Wait
call should always be used in aWhile
loop that waits for the condition.The original code does not use a
While
loop, but an If statement.lock (_lock)
{
// wrong: if (_queue.Count == 0)
while (_queue.Count == 0)
{
Monitor.Wait(_lock); //thread stays asleep here. why?
}
for a detailed explanation see the section "Signaling with Wait and Pulse" of part 4 in this article: Threading in C#