C# 工作线程唤醒争用条件

本文关键字:争用条件 唤醒 线程 工作 | 更新日期: 2023-09-27 18:32:29

下面的代码使用后台工作线程逐个处理工作项。每当工作项用完时,工作线程都会开始等待 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

C# 工作线程唤醒争用条件

您使用了错误的同步机制。 而不是 MRE 只需使用信号量。 然后,信号量将表示尚未处理的项目数。 您可以将其设置为添加一个,或等待它将其减少一个。 没有if,您总是执行每个信号量操作,因此没有竞争条件。

也就是说,您可以完全避免该问题。 与其自己管理同步原语,不如使用 BlockingCollection . 让生产者添加项目,消费者消费它们。 同步将由该类为您处理,并且可能比您的实现更有效。

我倾向于使用当前的工作项计数器并递增和递减该计数器。 您可以将处理器线程转换为一个循环,该循环正在查看该计数器,然后休眠,而不是运行一次就完成了。 这样,无论您在添加项目时身在何处,您距离正在处理的项目只有 1 个睡眠周期。