10

我正在使用condition_variableVisual Studio 2019。该condition_variable.wait_for()函数在std::cv_status::no_timeout没有任何通知的情况下返回。

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

std::condition_variable cv;
std::mutex mtx;
bool called = false;

void printThread()
{
    std::unique_lock<std::mutex> lck(mtx);
    while (std::cv_status::timeout == cv.wait_for(lck, std::chrono::seconds(1)))
    {
        std::cout << "*";
    }
    std::cout << "thread exits" << std::endl;
}

int main()
{
    std::thread th(printThread);
    th.join();
    std::cout << "program exits" << std::endl;
}

我认为代码永远不会退出并继续打印*,但它会在打印一些后退出*

这是输出:

********************************************************************thread exits
program exits

为什么会这样?是不是所谓的“虚假唤醒”?</p>

4

2 回答 2

11

是的,这是一个“虚假唤醒”。这在cppreference.com 的参考页面上进行了wait_for解释:

它也可能被虚假地解除阻塞。解除阻塞时,无论什么原因,都会重新获取锁并退出 wait_for()。

翻译:你的电脑里有小精灵。他们偶尔会脾气暴躁。如果他们确实脾气暴躁,wait_for请在请求的超时到期之前返回。当这种情况发生时:

返回值

  1. 如果 rel_time 指定的相对超时过期,则 std::cv_status::timeout,否则为 std::cv_status::no_timeout。

这似乎正是您所看到的。C++ 标准允许 C++ 实现wait_for出于任意原因过早返回,除非您确实wait_for在超时到期时返回,否则您将no_timeout得到什么。

您可能想知道为什么wait_for(以及其他几个类似的功能)可能会决定举手并“虚假地”返回。但那将是一个不同的问题......

于 2020-11-20T13:21:57.347 回答
0

正如已经解释的那样,它正在唤醒到期spurious wakeup。这样的事情使功能wait_for完全无用。wait_until解决方案是在进入等待循环之前使用保存当前时间:

int count = 1;
std::mutex mutex;
std::condition_variable condition_variable;

void wait() {
    std::unique_lock<std::mutex> lock(mutex);
    count--;

    int timeout = 1000; // 1 second
    std::chrono::time_point<std::chrono::system_clock> timenow = 
        std::chrono::system_clock::now();

    while(count < 0) {
        std::cv_status status = condition_variable.wait_until(
            lock, 
            timenow + std::chrono::duration<double,std::ratio<1,1000>>(timeout));

        if ( std::cv_status::timeout == status) {
            count++;
            break;
        }
    }
}
于 2021-04-23T20:44:22.933 回答