【问题标题】:Monitor.Pulse loses signals?Monitor.Pulse 丢失信号?
【发布时间】:2012-08-02 22:03:03
【问题描述】:

我有这个生产者/消费者代码:

主要:

static void Main()
{
    using(PCQueue q = new PCQueue(2))
    {
        for(int i = 0; i < 10; i++)
        {
            int itemNumber = i; // To avoid the captured variable trap
            q.EnqueueItem(() = > {
                Thread.Sleep(1000); // Simulate time-consuming work
                Console.Write(" Task" + itemNumber);
            });
        }
        Console.WriteLine("Enqueued 10 items");
        Console.WriteLine("Waiting for items to complete...");
    }

}

类:

   public class PCQueue: IDisposable
  {
      readonly object _locker = new object();
      Thread[] _workers;
      Queue < Action > _itemQ = new Queue < Action > ();
      public PCQueue(int workerCount)
      {
          _workers = new Thread[workerCount];
          // Create and start a separate thread for each worker
          for(int i = 0; i < workerCount; i++)
          (_workers[i] = new Thread(Consume)).Start();
      }
      public void Dispose()
      {
          // Enqueue one null item per worker to make each exit.
          foreach(Thread worker in _workers) EnqueueItem(null);
      }
      public void EnqueueItem(Action item)
      {
          lock(_locker)
          {
              _itemQ.Enqueue(item); // We must pulse because we're
              Monitor.Pulse(_locker); // changing a blocking condition.
          }
      }
      void Consume()
      {
          while(true) // Keep consuming until
          { // told otherwise.
              Action item;
              lock(_locker)
              {
                  while(_itemQ.Count == 0) Monitor.Wait(_locker);
                  item = _itemQ.Dequeue();
              }
              if(item == null) return; // This signals our exit.
              item(); // Execute item.
          }
      }
  }

问题:

假设执行item(); 需要很长时间。

1) we enqueue a new work and pulse. ( 1 consumer is busy now)
2) we enqueue a new work and pulse. ( second consumer is busy now)
3) we enqueue a new work and pulse. 

现在呢?两个线程都忙!

know 说脉搏会丢失(或不会?)

唯一的解决办法是改成AutoResetEvent吗?

【问题讨论】:

  • System.Collections.Concurrent.BlockingCollection 有什么问题?如果你想DIY,你可以使用System.Threading.Semaphore 和一个锁。事件不是生产者-消费者队列的合适解决方案 - 我不知道为什么这么多开发人员被欺骗使用它们来实现这样的目的。
  • @MartinJames 没有错。我只想知道如何增强代码,并检查我的假设是否正确。
  • @MartinJames 我想您将不得不向 Joe Albahari 询问您的问题。books.google.co.il/…
  • 使用信号量 - 它可以与多个生产者/消费者一起正常工作。 AutoResetEvent 可能与多个生产者/消费者一起正常工作,也可能无法正常工作。我从来没有费心去测试它,因为它只是不适合使用的同步器。
  • 你真的发现问题了吗?

标签: c# .net multithreading monitor


【解决方案1】:

现在呢?两个线程都很忙!
我知道脉搏会丢失(或不会?)

是的,当您的(所有)线程忙于执行 Item() 调用时,会丢失一个 Pulse。

但这并不一定是个问题,你在每个 Enqueue() 之后都在脉冲,基本上只有当 queue.Count 从 0 变为 1 时才需要脉冲。然后你需要更多的脉冲。

但是当您尝试优化脉冲数时,您可能会遇到麻烦。 Wait/Pulse 是无状态的这一事实确实意味着您应该谨慎使用它。

【讨论】:

  • Henk,我不明白。 (对不起)。 基本上只有在排队时才需要脉冲...好吧,我正在排队,但是脉冲丢失了...。它可能导致一个工作项没有得到处理的情况。对吗?
  • 愚弄我,我没有看while循环。它会扫描到 0。所以基本上我可以只用 2 个脉冲推送 1000 个项目,队列将被消化到 0。(对吗?)
  • 所需的脉冲数取决于生产者和消费者之间的速度差异。在这种情况下,消费者很慢,您只需要 2 个脉冲,正确。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-10
  • 1970-01-01
  • 1970-01-01
  • 2011-03-24
  • 1970-01-01
  • 2014-05-24
  • 1970-01-01
相关资源
最近更新 更多