【问题标题】:std::condition_variable predictable spurious wake-ups?std::condition_variable 可预测的虚假唤醒?
【发布时间】:2021-01-02 16:38:15
【问题描述】:

我遇到了这种有趣的虚假唤醒行为。考虑这个简单的演示代码:

#include <iostream>
#include <chrono>
#include <thread>
#include <condition_variable>
#include <mutex>

using namespace std;  // I know
using namespace std::chrono;
using namespace std::chrono_literals;

mutex mtx; // used for cv and synchronized access to counter
condition_variable cv;
int counter = 0; // (1)
bool keep_running = true; // flag for signaling an exit condition

int main()
{
    // thread that decrements counter every time it is woken up and the counter is > 0
    thread t([&] {
        while (keep_running)
        {
            unique_lock<mutex> lock(mtx);

            cv.wait(lock, [&] {
                cout << "Woken up" << endl;
                return !keep_running || counter > 0;
            });
            
            if (!keep_running) {  // check for exit condition
                break;
            }

            --counter;
        }
    });
    
    this_thread::sleep_for(1s);  // some work

    unique_lock<mutex> lock(mtx);
    counter = 5;  // set the counter
    cout << "Notifying" << endl;
    lock.unlock();
    cv.notify_one(); // wake the thread up

    this_thread::sleep_for(1s);  // some more work

    cout << "Exiting" << endl;
    lock.lock();
    keep_running = false; // ask the thread to exit
    lock.unlock();
    cv.notify_one(); // wake up one last time
    t.join(); // join and exit
    cout << "Counter: " << counter << endl;
}

使用g++ cv_test.cpp -o cv_test -pthread 编译并执行会产生以下输出:

Woken up
Notifying
Woken up
Woken up
Woken up
Woken up
Woken up
Woken up
Exiting
Woken up
Counter: 0

请注意,我只调用了一次notify_one,但线程会不断被唤醒,直到谓词返回 false。无论计数器初始化为什么,线程都会被唤醒,直到它变为 0(即谓词)。

即使在执行开始时,线程也会被唤醒一次,好像是为了“检查”谓词是否返回 false。因此,如果我将计数器初始化为正值:int counter = 3; // (1),则虚假唤醒似乎“确保”谓词在调用第一个 notify_one 之前返回 false。

我的问题是,这真的是一个功能吗?可以依赖它吗?有没有关于这种行为的文档?

PS。我知道在等待 condition_variable 之前,可以通过简单检查计数器(读取:工作队列长度)来修复这个工作线程,但是这种虚假唤醒的可预测行为引起了我的兴趣。

【问题讨论】:

标签: c++ multithreading condition-variable


【解决方案1】:

我在发布这个问题后立即意识到condition_variable::wait 的重载(如here 所述)相当于:

while (!pred()) {
    wait(lock);
}

我想象它等同于do while。所以这里真的没有虚假的唤醒。只是它根本没有等到谓词返回 false。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-06-16
    • 2011-06-07
    • 1970-01-01
    • 2013-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多