【问题标题】:C# PulseAll doesn't wake sleeping threadsC# PulseAll 不会唤醒睡眠线程
【发布时间】:2011-07-29 06:09:45
【问题描述】:

我有一种情况,有时在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.04.08: 更多信息 - 只有一个消费者线程。所以理论上 Pulse 就足够了。一旦达到状态,消费者线程保持睡眠状态,我可以继续将项目排入队列并随后调用PulseAll,而无法唤醒睡眠线程。我放置了一个断点 [1],它在所描述的情况下永远不会被击中。因此,我相信这不是 MSDN 页面中描述的 Pulse/Monitor 死锁问题。

【问题讨论】:

  • Monitor.Wait 释放锁 Daniel.
  • 你是对的,我不知道。
  • @Hans Passant - 我看不出这个问题/答案如何适用于此。正如您在给定答案中建议的那样,我确实在队列对象周围有一个lock
  • 那个问题是关于 exact 相同的代码。使用或丢失它,由您决定。

标签: c# multithreading


【解决方案1】:

您确定线程处于休眠状态吗?您的代码调用了_queue.Dequeue,如果队列中没有项目,它将引发异常。所以如果两个线程都在等待锁,当Add方法入队一个项目并调用PulseAll时,两个线程都会被释放。第一个线程将调用Dequeue 并获取队列中唯一的项目。下一个线程将调用Dequeue 并抛出异常。如果您正在捕获并吞下该异常,您将永远看不到它。并且由于异常已经逃脱了while 循环,线程终止并且队列将开始填充。

另外,虽然我怀疑这对您来说是个问题,但请参阅 http://msdn.microsoft.com/en-us/library/system.threading.monitor.pulse.aspx,其中谈到了使用 PulsePulseAll 的潜在死锁。

【讨论】:

  • 队列中只有一个消费者,所以我怀疑是否会抛出任何异常。一直以来,当一个线程试图使一个项目出队时,我都会遇到一个断点。
  • 该问题已通过架构更改得到解决。由于提供的信息,我接受了这个答案。
【解决方案2】:

当 Dequeue 函数没有等待时,可能是你在跳动吗?如果是这样,直到下一个脉冲才会触发等待。

查看Pulse上的重要说明

【讨论】:

  • 正如我上面提到的,队列已满。我可以随心所欲地跳动,线程保持在标有注释的位置。我可以在 Visual Studio 2008 中看到。
【解决方案3】:

Wait 调用应始终在等待条件的While 循环中使用。 原始代码使用While 循环,而是使用If 语句。

lock (_lock) { // wrong: if (_queue.Count == 0) while (_queue.Count == 0) { Monitor.Wait(_lock); //thread stays asleep here. why? }

详细解释请参见本文第 4 部分的“使用等待和脉冲发送信号”部分:Threading in C#

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-07-29
    • 1970-01-01
    • 2011-06-01
    • 2018-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-28
    相关资源
    最近更新 更多