0

我目前正在为单个线程使用 ManualResetEvent 以等待多个线程将某些内容添加到线程管理器的队列中。如果线程管理器使用手动重置事件接收到信号,它将使添加的项目出列并进行进一步处理。我唯一的问题是,如果触发了多个集合,则不会处理其他队列项。(见B 点

while (IsThreadRunning)
{
    // A: My workaround is to check if queue has item, if not then wait for other thread to set the event
    if (DataQueue.Count <= 0)
    {
        ResetEvent.WaitOne();
    }

    // B: At this point two thread added item to the queue and did ResetEvent.Set() twice.
    if (DataQueue.Count > 0)
    {
        DataQueue.Dequeue();
    }

    // Reset the event to avoid processor hog
    ResetEvent.Reset();
}

我在这里的解决方法是在A 点添加队列大小条件。是否有另一种方法来执行此操作以避免死锁?

注意:在使用 ManualResetEvent 的示例中给出的通常场景是单个线程上有多个线程等待(ManualResetEvent.Wait)事件,但这里是多个线程触发(ManualResetEvent.Set)事件。是否有其他用于此场景的类?

4

2 回答 2

1

您可以处理队列中的所有项目(如果有),然后等待事件发出信号。

当事件发出信号时,立即将其重置。

如果在您处理完队列中的最后一项后发出事件信号,那么最糟糕的情况是您将检查队列并且它将是空的。

while (IsThreadRunning)
{
  while ( DataQueue.Count > 0 )
  {
    DataQueue.Dequeue();
  }
  ResetEvent.WaitOne();
  ResetEvent.Reset();
}
于 2012-02-28T01:41:15.797 回答
1

现在转储手动重置事件。不要为此使用任何类型的事件。使用信号量和锁。在 push 方法中,锁定队列,将对象推入队列,退出锁定语句块,然后发出信号量。在 pop 方法中,等待信号量,然后锁定队列,弹出对象并退出锁定语句块。

那是如果你真的想自制生产者-消费者队列。如果您想要一个已经工作的队列,请查看 BlockingCollection 类。

于 2012-02-28T01:43:25.703 回答