2013-09-23 24 views
1

以下代码使用后台工作线程逐个处理工作项目。只要工作项目用完,工作线程就会开始等待ManualResetEvent。主线程定期添加新的工作项并唤醒工作线程。C#工作线程唤醒竞争条件

醒来机制有竞争条件。如果主线程添加新项目,而工作线程位于*指定的位置,则工作线程不会被唤醒。

是否有一种简单且正确的方法来唤醒没有此问题的工作线程?

ManualResetEvent m_waitEvent; 

    // Worker thread processes work items one by one 
    void WorkerThread() 
    { 
     while (true) 
     { 
      m_waitEvent.WaitOne(); 
      bool noMoreItems = ProcessOneWorkItem(); 
      if (noMoreItems) 
      { 
       // * 
       m_waitEvent.Reset(); // No more items, wait for more 
      } 
     } 
    } 

    // Main thread code that adds a new work item 
    AddWorkItem(); 
    m_waitEvent.Set(); // Wake worker thread 
+3

'System.Collections.Concurrent.ConcurrentQueue'' System.Collections.Concurrent.BlockingCollection' – I4V

回答

3

您正在使用错误的同步机制。而不是MRE只是使用信号量。信号量将代表尚未处理的项目数量。您可以将其设置为添加一个,或者等待它减少一个。没有if,你总是做每个信号量的行动,因此没有竞争条件。

也就是说,你可以完全避免这个问题。您可以使用BlockingCollection而不是自己管理同步原语。生产者添加物品,消费者消费它们。所有同步都将由该类别为您处理,并且可能比您的实现更有效。

0

我倾向于使用当前工作项目计数器并递增和递减该计数器。你可以把你的处理器线程变成一个循环,看着那个柜台然后睡觉,而不是一次运行完成。这样,无论您何时添加物品,您都可以从正在处理的物品开始1个睡眠周期。