下面的代码使用后台工作线程逐个处理工作项。每当工作项用完时,工作线程都会开始等待 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
您使用了错误的同步机制。 而不是 MRE 只需使用信号量。 然后,信号量将表示尚未处理的项目数。 您可以将其设置为添加一个,或等待它将其减少一个。 没有if
,您总是执行每个信号量操作,因此没有竞争条件。
也就是说,您可以完全避免该问题。 与其自己管理同步原语,不如使用 BlockingCollection
. 让生产者添加项目,消费者消费它们。 同步将由该类为您处理,并且可能比您的实现更有效。
我倾向于使用当前的工作项计数器并递增和递减该计数器。 您可以将处理器线程转换为一个循环,该循环正在查看该计数器,然后休眠,而不是运行一次就完成了。 这样,无论您在添加项目时身在何处,您距离正在处理的项目只有 1 个睡眠周期。