C# PulseAll 不会唤醒休眠线程

发布于 2024-10-29 23:12:38 字数 1173 浏览 1 评论 0原文

我遇到一种情况,有时休眠线程不会被 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

且行且努力 2024-11-05 23:12:38

您确定线程处于休眠状态吗?您的代码调用了 _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 the Add method enqueues an item and calls PulseAll, both threads will be released. The first thread will call Dequeue and get the only item in the queue. The next thread will call Dequeue and throw an exception. If you're catching and swallowing that exception, you'll never see it. And since the exception has escaped the while 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 and PulseAll.

下壹個目標 2024-11-05 23:12:38

当 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

浮云落日 2024-11-05 23:12:38

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 a While 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#

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文