Reputation: 3645
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);
});
Upvotes: 4
Views: 6362
Reputation: 76523
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.
Upvotes: 3