C++11 c++;11条件_变量等待虚假唤醒不工作

C++11 c++;11条件_变量等待虚假唤醒不工作,c++11,condition-variable,C++11,Condition Variable,我试图使用条件变量编写一个简单的生产者/消费者 include <iostream> #include <thread> #include <condition_variable> #include <mutex> #include <chrono> #include <queue> #include <chrono> using namespace std; condition_variable cond_v

我试图使用
条件变量
编写一个简单的生产者/消费者

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;
}

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

错误的唤醒并不是经常发生的,你可以依靠它以你建议的方式打破循环。出现虚假唤醒的风险是当前条件变量实现的一个不幸的副作用,您必须对此加以说明,但无法保证何时(如果有)会出现虚假唤醒


如果要确保使用者线程不会在等待永不到来的通知时陷入困境,可以尝试改用
std::condition\u variable::wait\u for()
。它需要一个持续时间,如果持续时间到期,它将超时并重新请求锁。它可能被视为更接近繁忙的等待,但如果超时时间足够长,对性能的影响应该可以忽略不计。

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

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

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

现在它应该退出了。。。大多数时候。您仍然有一个可能的争用条件,因为在producer中,您设置了
done=true
,而没有持有锁。

@openyourmind Yes,而在OP的代码中,锁持有在使用者线程中。
while(!done && goods.empty())
{
    ...
}