Understanding the example of using std::condition_variable

徘徊边缘 提交于 2020-02-14 08:02:46

问题


There is example of using condition_variable taken from cppreference.com:

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

int main()
{
    std::queue<int> produced_nums;
    std::mutex m;
    std::condition_variable cond_var;
    bool done = false;
    bool notified = false;

    std::thread producer([&]() {
        for (int i = 0; i < 5; ++i) {
            std::this_thread::sleep_for(std::chrono::seconds(1));
            std::lock_guard<std::mutex> lock(m);
            std::cout << "producing " << i << '\n';
            produced_nums.push(i);
            notified = true;
            cond_var.notify_one();
        }   

        std::lock_guard<std::mutex> lock(m);  
        notified = true;
        done = true;
        cond_var.notify_one();
    }); 

    std::thread consumer([&]() {
        while (!done) {
            std::unique_lock<std::mutex> lock(m);
            while (!notified) {  // loop to avoid spurious wakeups
                cond_var.wait(lock);
            }   
            while (!produced_nums.empty()) {
                std::cout << "consuming " << produced_nums.front() << '\n';
                produced_nums.pop();
            }   
            notified = false;
        }   
    }); 

    producer.join();
    consumer.join();
}

If variable done comes true before the consumer thread is started, the consumer thread will not get any message. Indeed, sleep_for(seconds(1)) almost avoids such situation, but could it be possible in theory (or if don't have sleep in code)?

In my opinion correct version should look like this to force running consumer loop at least once:

std::thread consumer([&]() {
    std::unique_lock<std::mutex> lock(m);
    do {
        while (!notified || !done) {  // loop to avoid spurious wakeups
            cond_var.wait(lock);
        }   

        while (!produced_nums.empty()) {
            std::cout << "consuming " << produced_nums.front() << '\n';
            produced_nums.pop();
        }   

        notified = false;
    } while (!done);
}); 

回答1:


Yes, you are absolutely right: there is a (remote) possibility that the consumer thread will not start running until after done has been set. Further, the write to done in the producer thread and the read in the consumer thread produce a race condition, and the behavior is undefined. Same problem in your version. Wrap the mutex around the entire loop in each function. Sorry, don't have the energy to write the correct code.



来源:https://stackoverflow.com/questions/15733887/understanding-the-example-of-using-stdcondition-variable

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!