An example condition_variable::notify_one - c++

from
#include <iostream>
#include <condition_variable>
#include <thread>
#include <chrono>
using namespace std::chrono_literals;
std::condition_variable cv;
std::mutex cv_m;
int i = 0;
bool done = false;
void waits()
{
std::unique_lock<std::mutex> lk(cv_m);
std::cout << "Waiting... \n";
cv.wait(lk, []{return i == 1;});
std::cout << "...finished waiting; i == " << i << '\n';
done = true;
}
void signals()
{
std::this_thread::sleep_for(200ms);
std::cout << "Notifying falsely...\n";
cv.notify_one(); // waiting thread is notified with i == 0.
// cv.wait wakes up, checks i, and goes back to waiting
std::this_thread::sleep_for(300ms); // Add to make sure 'waits' thread wakes up**
std::unique_lock<std::mutex> lk(cv_m);
i = 1;
while (!done)
{
std::cout << "Notifying true change...\n";
lk.unlock();
cv.notify_one(); // waiting thread is notified with i == 1, cv.wait returns**
std::this_thread::sleep_for(300ms);
lk.lock();
}
}
int main()
{
std::thread t1(waits), t2(signals);
t1.join();
t2.join();
}
This is an example I got from cppreference. I have tried to execute the codes and observe the second notify seems not effected. Even I commented it out, the "signals" thread is still done.
Should it be put in the forever loop ??
Also if I add a wait before taking the cv_m mutex, seems it's working as expected

Related

How std::condition_variable and std::mutex works exactly?

I'm reading this std::condition_variable example:
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex m;
std::condition_variable cv;
std::string data;
bool ready = false;
bool processed = false;
void worker_thread()
{
// Wait until main() sends data
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, []{return ready;});
// after the wait, we own the lock.
std::cout << "Worker thread is processing data\n";
data += " after processing";
// Send data back to main()
processed = true;
std::cout << "Worker thread signals data processing completed\n";
// Manual unlocking is done before notifying, to avoid waking up
// the waiting thread only to block again (see notify_one for details)
lk.unlock();
cv.notify_one();
}
int main()
{
std::thread worker(worker_thread);
data = "Example data";
// send data to the worker thread
{
std::lock_guard<std::mutex> lk(m);
ready = true;
std::cout << "main() signals data ready for processing\n";
}
cv.notify_one();
// wait for the worker
{
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, []{return processed;});
}
std::cout << "Back in main(), data = " << data << '\n';
worker.join();
}
Let's focus on the beggining:
std::thread worker(worker_thread);
here, we start the worked, which will lock the mutex immediately:
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, []{return ready;});
Then, we lock the mutex on main to change the value of ready
{
std::lock_guard<std::mutex> lk(m);
ready = true;
std::cout << "main() signals data ready for processing\n";
}
but how is it possible that we even arrive at the line ready=true? The mutext m is blocked from the worked thread, so the line std::lock_guard<std::mutex> lk(m); will wait until the mutex m is unlocked. As I understand, when a mutex is locked and we try to lock it, we'll wait until it gets unlocked. However, it'll never get unlocked because the worked thread is waiting, therefore not releasing it.
In the link you have attached, note that the following
The wait operations atomically release the mutex and suspend the
execution of the thread.
Hence the line
cv.wait(lk, []{return ready;});
releases the mutex and suspends the execution of the thread until the condition variable is notified, a timeout expires (with wit_for()), or a spurious wake-up occurs, hence the thread is awakened, and the mutex is atomically reacquired
Here's another example that will give you the gist of the mechanism.
#include <cstdio>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>
std::mutex mtx;
std::condition_variable cv;
bool signal = 0;
void A()
{
while (1)
{
{
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [](){return signal;});
signal = 0;
}
printf("Lock release from th A\n");
}
}
int main()
{
std::thread th(A);
for (unsigned i = 0; i < 100; i++)
{
{
std::lock_guard<std::mutex> lock(mtx);
signal = 1;
}
cv.notify_one();
printf("Sending signal %i\n", i);
std::this_thread::sleep_for(std::chrono::seconds(5));
}
th.join();
return 0;
}

C++ - How not to miss multiple notifications from multiple threads?

In my application, many threads notify a waiting thread. Sometimes these notifications are very close to each other in time and the waiting thread misses the notification. Is there any easy way to counter this issue? A small example code is given below. In the code, the task2 notifies the waiting thread but the waiting thread, waitingForWork, miss the notification.
#include <condition_variable>
#include <iostream>
#include <thread>
std::mutex mutex_;
std::condition_variable condVar;
bool dataReady{ false };
void waitingForWork() {
for (int i = 0; i < 2; i++)
{
std::cout << "Waiting " << std::endl;
std::unique_lock<std::mutex> lck(mutex_);
condVar.wait(lck, [] { return dataReady; });
dataReady = false;
std::cout << "Running " << std::endl;
}
}
void task1() {
std::this_thread::sleep_for(std::chrono::milliseconds{ 45 });
std::lock_guard<std::mutex> lck(mutex_);
dataReady = true;
std::cout << "Task1 Done:" << std::endl;
condVar.notify_one();
}
void task2() {
std::this_thread::sleep_for(std::chrono::milliseconds{ 46 });
std::lock_guard<std::mutex> lck(mutex_);
dataReady = true;
std::cout << "Task2 Done" << std::endl;
condVar.notify_one();
}
int main() {
std::cout << std::endl;
std::thread t1(waitingForWork);
std::thread t2(task1);
std::thread t3(task2);
t1.join();
t2.join();
t3.join();
std::cout << std::endl;
system("pause");
}
It's a multiple producer single consumer problem. Which is described here:
Multiple consumer single producer problem
So basically you have to change your code in a way that each thread have to write notifications into a threadsafe queue.
And then your worker thread has to work on this queue and will not miss anymore notifications.

C++ - std::condition_variable notified by different threads

I am trying to notify an event from two different threads. Main thread wakes up on first notify_one() call but not on the second one. Is this the right way to use condition variable?
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
bool is_ready_1(false);
bool is_ready_2(false);
std::mutex m;
std::condition_variable cv;
void test1()
{
std::this_thread::sleep_for(std::chrono::seconds(3));
std::unique_lock<std::mutex> lk(m);
is_ready_1 = true;
cv.notify_one();
}
void test2()
{
std::this_thread::sleep_for(std::chrono::seconds(6));
std::unique_lock<std::mutex> lk(m);
is_ready_2 = true;
cv.notify_one();
}
int main()
{
std::thread t1(test1);
std::thread t2(test2);
std::unique_lock<std::mutex> lk(m);
while (!is_ready_1)
{
cv.wait(lk);
if (is_ready_1)
std::cout << "Spurious wake-1 up!\n";
}
while (!is_ready_2)
{
cv.wait(lk);
if (is_ready_2)
std::cout << "Spurious wake-2 up!\n";
}
t1.join();
t2.join();
system("pause");
}
Try this code. Note that a condition variable accepts a predicate that first checks if the the condition is met, and then takes the lock. When you notify the variable, it runs the predicate (without taking the lock), if the condition is true, the thread will own the lock else the calling thread will keep waiting for the next notification.
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
auto is_ready_1=false;
auto is_ready_2=false;
std::mutex m;
std::condition_variable cv;
void test1()
{
std::this_thread::sleep_for(std::chrono::seconds(3));
std::unique_lock<std::mutex> lk(m);
is_ready_1 = true;
cv.notify_one();
}
void test2()
{
std::this_thread::sleep_for(std::chrono::seconds(6));
std::unique_lock<std::mutex> lk(m);
is_ready_2 = true;
cv.notify_one();
}
int main()
{
std::thread t1(test1);
std::thread t2(test2);
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, [] {
if (!is_ready_1)
{
std::cout << "Spurious 1" << std::endl;
}
return is_ready_1;
});
//preceding line must clear before this is executed
cv.wait(lk, [] {
if (!is_ready_2)
{
std::cout << "Spurious 1" << std::endl;
}
return is_ready_2;
});
t1.join();
t2.join();
system("pause");
}
Also on Windows 10, I see two spurious wakeup events, I suspect these happen when the thread is woken up from sleep.

program went into dead lock using condition variable in c++11

I am currently trying to learn how to use a condition_variable for thread synchronization. For testing, I have made the demo application shown below. When I start it, it runs into a dead lock. I know the location where this happens, but I'm unable to understand why the deadlock occurs.
I know that a condition_variable's wait function will automatically unlock the mutex when the condition is not true, so the main thread should not be blocked in the second pass. But it is just this what happens.
Could anybody explain why?
#include <thread>
#include <condition_variable>
#include <iostream>
bool flag = false;
std::mutex g_mutex;
std::condition_variable cv;
void threadProc()
{
std::unique_lock<std::mutex> lck(g_mutex);
while (true)
{
static int count = 0;
std::cout << "wait for flag" << ++count << std::endl;
cv.wait(lck, []() {return flag; }); // !!!It will blocked at the second round
std::cout << "flag is true " << count << std::endl;
flag = false;
lck.unlock();
}
}
int main(int argc, char *argv[])
{
std::thread t(threadProc);
while (true)
{
static int count = 0;
{
std::lock_guard<std::mutex> guard(g_mutex); // !!!It will blocked at the second round
flag = true;
std::cout << "set flag " << ++count << std::endl;
}
cv.notify_one();
std::this_thread::sleep_for(std::chrono::seconds(1));
}
t.join();
return 0;
}
I know that a condition_variable's wait function will automatically unlock the mutex when the condition is not true.
Um..., yes..., Just to be absolutely clear, cv.wait(lck, f) does this:
while(! f()) {
cv.wait(lck);
}
And each call to cv.wait(lck) will;
unlock lck,
wait until some other thread calls cv.notify_one() or cv.notify_all(),
re-lock lck, and then
return.
You can fix the problem by moving the unique_lock(...) statement inside the while loop. As it is now, you're attempting to unlock lck on round 2 but it was not in a locked state, since, after round 1 you never locked it again.

Understanding the example of using std::condition_variable

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