c ++ 11 condition_variable等待虚假唤醒不起作用

时间:2018-03-30 08:47:15

标签: c++11 condition-variable

我尝试使用condition_variable

编写一个简单的生产者/消费者
include <iostream>
#include <thread>
#include <condition_variable>
#include <mutex>
#include <chrono>
#include <queue>
#include <chrono>
using namespace std;

condition_variable cond_var;
mutex m;
int main()
{
    int c = 0;
    bool done = false;
    cout << boolalpha;
    queue<int> goods;

    thread producer([&](){
        for (int i = 0; i < 10; ++i) {
            m.lock();
            goods.push(i);
            c++;
            cout << "produce " << i << endl;
            m.unlock();
            cond_var.notify_one();
            this_thread::sleep_for(chrono::milliseconds(100));
        }
        done = true;
        cout << "producer done." << endl;
        cond_var.notify_one();
    });

    thread consumer([&](){
        unique_lock<mutex> lock(m);
        while(!done || !goods.empty()){
            /*
            cond_var.wait(lock, [&goods, &done](){
                        cout << "spurious wake check" << done <<endl;
                        return (!goods.empty() || done);
            });
            */  
            while(goods.empty())
            {
                cout<< "consumer wait" <<endl;
                cout<< "consumer owns lock " << lock.owns_lock() <<endl;
                cond_var.wait(lock);
            }
            if (!goods.empty()){
                cout << "consume " << goods.front()<<endl;
                goods.pop();
                c--;
            }
        }
    });

    producer.join();
    consumer.join();
    cout << "Net: " << c << endl;
}

我现在遇到的问题是当消费者在生产者设置done之前消耗最后一个项目到true时,消费者线程将停留在

 while(goods.empty())
            {
                cout<< "consumer wait" <<endl;
                cout<< "consumer owns lock " << lock.owns_lock() <<endl;
                cond_var.wait(lock);
            }

我的理解是cond_var.wait(lock)会虚假地醒来,从而退出while(good.empty())循环,但似乎并非如此?

2 个答案:

答案 0 :(得分:0)

虚假的唤醒并不是一种经常性的发生,你可以依靠它以你建议的方式打破一个循环。虚假唤醒的风险是当前条件变量实现的一个不幸的副作用,您必须考虑这些因素,但不能保证何时(如果有的话)您会遇到虚假的唤醒。

如果您想确保消费者线程无法等待永远不会发出的通知,您可以尝试使用std::condition_variable::wait_for()代替。它需要一段时间并且会超时并在持续时间到期时重新获取锁定。它可能被视为更接近忙碌的等待,但如果超时足够长,对性能的影响应该可以忽略不计。

答案 1 :(得分:0)

正如@Karlinde所说,顾名思义,虚假的唤醒并不能保证会发生。相反,它们通常根本不会发生。

但是,即使发生虚假的唤醒,也不会解决你的问题:你的程序中只有一个无限循环。生产者停止后,goods.empty()为真,它永远不会再改变。所以将while循环更改为:

while(!done && goods.empty())
{
    ...
}

现在它应该退出......大部分时间。你仍然有可能的竞争条件,因为在制作人中,你设置done = true而不持有锁。