2012-02-28 75 views
1

我目前使用ManualResetEvent为单个线程等待多个线程添加一些东西到一个线程管理器的队列。如果线程管理器使用手动重置事件接收到信号,它将使添加的项目出列并进行进一步处理。我唯一的问题是,如果有多个设置被触发,那么其他队列项目将不会被处理。 (见B点ManualResetEvent大小检查是否足以等待多个线程?

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)事件。是否有其他课程用于此场景?

+1

为什么不简单地改变你的第二,如果一段时间? – 2012-02-28 01:40:02

回答

1

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

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

如果事件在处理队列中的最后一个项目后发出信号,则会发生的最坏情况是您将检查队列并将其清空。

while (IsThreadRunning) 
{ 
    while (DataQueue.Count > 0) 
    { 
    DataQueue.Dequeue(); 
    } 
    ResetEvent.WaitOne(); 
    ResetEvent.Reset(); 
} 
1

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

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

+0

这是你的吗? http://www.dijksterhuis.org/using-semaphores-in-c/ – Nap 2012-02-28 02:26:37

+0

@Nap - 不。使用队列锁和信号量(如果队列有界,则有2个信号量)是实现生产者 - 消费者队列的'计算机科学101'方式。我不知道开发人员如何使用事件而不是信号量来寻找具有计数器的同步机制。 – 2012-02-28 09:00:52