最后 notify_all 没有触发最后 conditional_variable.wait

Last notify_all isn't triggering last conditional_variable.wait

我想做什么

嗨,我有两种类型的线程,主线程和工作线程,其中工作线程等于 CPU 上的核心数,我想做的是当主线程需要时要调用更新,我将一个名为 Updating 的布尔值设置为 true 并调用 condition_variable(cv).notify_all 然后每个线程将完成其工作,完成后它将递增一个 atomic_int 称为 CoresCompleted,然后是 cv.notify_all这样主线程可以检查是否所有工作都完成然后它将等待变量 Updating 为 false 这样可以确保所有其他线程完成并且它不会再次更新,一旦完成主线程设置更新为假并通知所有人。

代码

主要

void UpdateManager::Update() {

    //Prepare Update
    CoresCompleted = 0;
    Updating = true;

    //Notify Update Started
    cv.notify_all();

    //Wait for Update to end
    auto Pre = high_resolution_clock::now();
    cv.wait(lk, [] { return (int)UpdateManager::CoresCompleted >= (int)UpdateManager::ProcessorCount; });
    auto Now = high_resolution_clock::now();
    auto UpdateTime = duration_cast<nanoseconds>(Now - Pre);
    
    //End Update and nofity threads
    Updating = false;
    cv.notify_all();
}

工人

void CoreGroup::Work() {

    Working = true;
    unique_lock<mutex> lk(UpdateManager::m);

    while (Working) {
        
        //Wait For Update To Start
        UpdateManager::cv.wait(lk, []{ return UpdateManager::Updating; });

        if (!Working)
            return;

        //Do Work
        size_t Size = Groups.size();

        auto Pre = high_resolution_clock::now();

        for (size_t Index = 0; Index < Size; Index++)
            Groups[Index]->Update();

        auto Now = high_resolution_clock::now();
        UpdateTime = duration_cast<nanoseconds>(Now - Pre);
        
        //Increment CoresCompleted And Notify All
        UpdateManager::CoresCompleted++;
        UpdateManager::cv.notify_all();

        //Wait For Update To End
        UpdateManager::cv.wait(lk, []{ return !UpdateManager::Updating; });
    }
}

问题

一旦工作人员到达他们等待更新为假的最后等待,他们就会卡住并且永远不会离开,由于某种原因,主线程中的最后一个 notify_all 没有到达工作人员,我尝试搜索并查找了很多示例,但我无法弄清楚为什么它没有触发,也许我没有理解 cv 和锁是如何工作的,知道为什么会发生这种情况以及如何解决吗?

你的代码是这样工作的: Update 中的一些等待在通知时结束:

cv.wait(lk, [] { return (int)UpdateManager::CoresCompleted >= (int)UpdateManager::ProcessorCount; });

它不再等待,需要锁定互斥量。继续做它的事情然后到达终点并通知另一个线程他们可以继续使用这一行:

cv.notify_all();

但这是谎言,他们不能继续工作,因为你持有锁。释放它,他们将继续工作:

void UpdateManager::Update() {
    <...>
    //End Update and nofity threads
    Updating = false;
    lk.unlock();
    cv.notify_all();
}

这可能不是此代码中的唯一问题,但我假设您在进入 Update 方法之前锁定了互斥锁,或者保证它在另一个方法之前运行(Work ).