以下代码使用后台工作线程逐个处理工作项。每当工作项用尽时,工作线程就开始等待ManualResetEvent。主线程定期添加新工作项并唤醒工作线程。
唤醒机制具有竞争条件。如果主线程添加了一个新项,而工作线程位于*所指示的位置,则工作线程不会被唤醒。
是否有一种简单而正确的方法来唤醒没有此问题的工作线程?
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
答案 0 :(得分:3)
您使用的是错误的同步机制。而不是MRE只使用信号量。然后,信号量将表示尚待处理的项目数。您可以将其设置为添加一个,或者等待它将其减少一个。没有if
,你总是做每个信号量动作,因此没有竞争条件。
那就是说,你可以完全避免这个问题。您可以自己使用BlockingCollection
,而不是自己管理同步原语。让生产者添加项目,消费者使用它们。同级将由该类为您完成,并且可能比您的实现更有效。
答案 1 :(得分:0)
我倾向于使用当前的工作项计数器并递增和递减该计数器。您可以将处理器线程转换为循环,查看该计数器然后休眠而不是运行一次并完成。这样,无论您在何时添加项目,您都可以从正在处理的项目中获得1个睡眠周期。