condition_variable wait_for in C++ - c++

I am working with condition_variable on Visual studio 2019. The condition_variable.wait_for() function returns std::cv_status::no_timeout without any notification.
#include <iostream>
#include <thread>
#include <chrono>
#include <mutex>
std::condition_variable cv;
std::mutex mtx;
bool called = false;
void printThread()
{
std::unique_lock<std::mutex> lck(mtx);
while (std::cv_status::timeout == cv.wait_for(lck, std::chrono::seconds(1)))
{
std::cout << "*";
}
std::cout << "thread exits" << std::endl;
}
int main()
{
std::thread th(printThread);
th.join();
std::cout << "program exits" << std::endl;
}
I think the code will never exit and keep printing *, but it exits after printing some *.
Here is the output:
********************************************************************thread exits
program exits
Why does this happen? Is it the so-called "spurious wakeups"?

Yes, it's a "spurious wakeup". This is explained on cppreference.com's reference page for wait_for:
It may also be unblocked spuriously. When unblocked, regardless of the
reason, lock is reacquired and wait_for() exits.
Translation: there are gremlins in your computer. They get grumpy, occasionally. And if they do get grumpy, wait_for returns before the requested timeout expires. And when that happens:
Return value
std::cv_status::timeout if the relative timeout specified by
rel_time expired, std::cv_status::no_timeout otherwise.
And that seems to be exactly what you're seeing. The C++ standard permits a C++ implementation to return from wait_for prematurely, for arbitrary reasons, and unless you do return from wait_for when the timeout expires, no_timeout is what you get.
You might be wondering why wait_for (and several other similar functions) may decide to throw up their hands and return "spuriously". But that would be a different question...

As already explained, it is waking up due spurious wakeup. Such thing make the function wait_for completely useless. The solution is to use the wait_until saving the current time before entering the wait loop:
int count = 1;
std::mutex mutex;
std::condition_variable condition_variable;
void wait() {
std::unique_lock<std::mutex> lock(mutex);
count--;
int timeout = 1000; // 1 second
std::chrono::time_point<std::chrono::system_clock> timenow =
std::chrono::system_clock::now();
while(count < 0) {
std::cv_status status = condition_variable.wait_until(
lock,
timenow + std::chrono::duration<double,std::ratio<1,1000>>(timeout));
if ( std::cv_status::timeout == status) {
count++;
break;
}
}
}

Related

How to correctly wait for condition variable timeout

I'm working on simple cancellation mechanism. But I have found problem with waiting for timeout on condition variable.
Lets consider the sample program from:
https://www.cplusplus.com/reference/condition_variable/condition_variable/wait_for/
It looks like this sample is broken. If someone would provide the data very fast then the program would go into infinite loop. To visualize it I did little modification to the sample program:
#include <iostream> // std::cout
#include <thread> // std::thread
#include <chrono> // std::chrono::seconds
#include <mutex> // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable, std::cv_status
using namespace std::chrono_literals;
std::condition_variable cv;
int value = -1;
void compute() {
value = 0;;
cv.notify_one();
}
int main()
{
std::thread th(compute);
std::this_thread::sleep_for(1s);
std::mutex mtx;
std::unique_lock<std::mutex> lck(mtx);
while (cv.wait_for(lck, std::chrono::seconds(1)) == std::cv_status::timeout) {
std::cout << '.' << std::endl;
}
std::cout << "You entered: " << value << '\n';
th.join();
return 0;
}
As I can't type as fast I just set the value to 0 and execute notify_one.
On the main thread I simulate simple delay. sleep_for(1s).
Finally the program does not see the notify_one and loops infinitely.
The output is: .....
My question is how to implement it correctly ?
I would like to know also if the waiting was stopped by timeout.
If the notify happens before the wait then it indeed gets "lost".
Most usage of CVs also require a flag of some sort which should be checked in the predicate. You already have this flag - value. Just use this as a predicate:
EDIT: Removed wrong code.
Note that as a separate matter you should protect the writing to value with your mutex or you're likely to hit UB. Which means you need to make your mutex global along with the CV/Flag.
Better way:
auto endTime = std::chrono::now() + std::chrono::seconds(1);
while(flag != 0)
{
auto res = cv.wait_until(lck, endTime);
if (res == std::cv_status::timeout)
{
// Add Timeout logic here
break;
}
}

std::condition_variable predictable spurious wake-ups?

I ran into this interesting behavior of spurious wake-ups. Consider this simple demo code:
#include <iostream>
#include <chrono>
#include <thread>
#include <condition_variable>
#include <mutex>
using namespace std; // I know
using namespace std::chrono;
using namespace std::chrono_literals;
mutex mtx; // used for cv and synchronized access to counter
condition_variable cv;
int counter = 0; // (1)
bool keep_running = true; // flag for signaling an exit condition
int main()
{
// thread that decrements counter every time it is woken up and the counter is > 0
thread t([&] {
while (keep_running)
{
unique_lock<mutex> lock(mtx);
cv.wait(lock, [&] {
cout << "Woken up" << endl;
return !keep_running || counter > 0;
});
if (!keep_running) { // check for exit condition
break;
}
--counter;
}
});
this_thread::sleep_for(1s); // some work
unique_lock<mutex> lock(mtx);
counter = 5; // set the counter
cout << "Notifying" << endl;
lock.unlock();
cv.notify_one(); // wake the thread up
this_thread::sleep_for(1s); // some more work
cout << "Exiting" << endl;
lock.lock();
keep_running = false; // ask the thread to exit
lock.unlock();
cv.notify_one(); // wake up one last time
t.join(); // join and exit
cout << "Counter: " << counter << endl;
}
Compiling with g++ cv_test.cpp -o cv_test -pthread and executing produces the following output:
Woken up
Notifying
Woken up
Woken up
Woken up
Woken up
Woken up
Woken up
Exiting
Woken up
Counter: 0
Notice that I call notify_one only once, but the thread is woken up continuously until the predicate returns false. No matter what the counter is initialized to, the thread is woken up until it goes to 0 (which is the predicate).
Even at the beginning of the execution, the thread is woken up once as if to "check" that the predicate returns false. Consequently, if I initialize the counter to a positive value: int counter = 3; // (1), the spurious wake-ups seem to "ensure" the predicate returns false even before the first notify_one is called.
My question is, is this really a feature and can it be relied upon? Is there any documentation on this behavior?
PS. I know this worker thread can be fixed by a simple check for the counter (read: work queue length) before waiting on the condition_variable, but this kind of predictable behavior of the spurious wake-ups intrigued me.
I realized immediately after I posted this question that this overload of condition_variable::wait (as described here) is equivalent to:
while (!pred()) {
wait(lock);
}
I was imagining it being equivalent to a do while instead. So really there are no spurious wake-ups here. Just that it wasn't waiting at all until the predicate returned false.

Is a condition variable's .wait_for() an efficient way to perform a background task at a specific interval?

I need to run an activity every so often while my program is running. In production code this is configurable with a default of 30 minutes, but in the example below I've used 5 seconds. Previously I had a std::thread that would loop once per second checking to see if it was time to run the activity OR if the program was closed. This allowed me to close the program at any time without having the .join() on the activity's thread block my application's exit waiting for its next iteration. At any moment it was less than a second away from checking to see if it should close or perform the activity.
I do not like the idea of wasting time checking every second for an activity that may only occur every 30 minutes while the program is running, so I attempted to switch it to a condition variable. I've included a small example of my implementation below. I want to be sure I'm using the right tools to do this. The issue I see with my code is unnecessary calls of the lambda expression which I'll explain below.
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
bool asking_thread_to_quit;
std::mutex cv_mutex;
std::condition_variable cv;
void RunThread()
{
{
std::lock_guard<std::mutex> lock(cv_mutex);
asking_thread_to_quit = false;
}
std::cout << "Started RunThread." << std::endl;
while(true)
{
{
std::unique_lock<std::mutex> lock(cv_mutex);
std::chrono::seconds delay(5);
if(cv.wait_for(lock, delay, [] { std::cout << "WAKEUP" << std::endl; return asking_thread_to_quit; })) // timed out
{
std::cout << "Breaking RunThread Loop." << std::endl;
break;
}
}
std::cout << "TIMER CODE!" << std::endl;
}
}
int main(int argc, char *argv[])
{
std::cout << "Program Started" << std::endl;
std::thread run_thread(RunThread);
// This is where the rest of the program would be implemented, but for the sake of this example, simply wait for user input to allow the thread to run in the background:
char test;
std::cin >> test;
{
std::lock_guard<std::mutex> lock(cv_mutex);
asking_thread_to_quit = true;
}
cv.notify_all();
std::cout << "Joining RunThread..." << std::endl;
run_thread.join();
std::cout << "RunThread Joined." << std::endl;
return 0;
}
If you execute the program and allow for one 5-second iteration to pass, it gives the following output:
Program Started
Started RunThread.
WAKEUP
WAKEUP
TIMER CODE!
WAKEUP
q <-- I typed this to quit.
Joining RunThread...
WAKEUP
Breaking RunThread Loop.
RunThread Joined.
You can see that it does the following:
(WAKEUP) Performs the check prior to waiting
Wait for five seconds
(WAKEUP) Performs the check
(TIMER CODE!) Executes the activity
(WAKEUP) Performs the check again before going back to waiting
Step 5 seems unnecessary as I just performed it a split second ago, but I believe it is necessary as .wait_for() doesn't know I'm using it inside of a while(true) loop. Is this something I'm stuck with, or is there a way to remove the initial check in the .wait_for() call? I'm guessing there is not as it would allow for the system to .wait_for() something that it doesn't need to wait for. This is what leads me to wonder if I'm using the right language features to begin with. Is there a better way?
The Answer
The answer given below goes into detail on other issues with my code as well as sparked an informative related conversation. I'm going to accept that answer as it helped me the most, but the quick answer to the question seems to be this:
asking_thread_to_quit could have been set to true during the TIMER CODE! section, requiring another check prior to waiting on the condition variable again.
Your code has a few issues with it.
void RunThread()
{
asking_thread_to_quit = false;
This is a race condition. You shouldn't modify a non-atomic shared variable in two different threads without synchronization.
std::cout << "Started RunThread." << std::endl;
while(true)
{
std::unique_lock<std::mutex> lock(cv_mutex);
std::chrono::seconds delay(5);
First using namespace std::literals::chrono_literals;. Then use 5s.
if(cv.wait_for(lock, delay, [] { std::cout << "WAKEUP" << std::endl; return asking_thread_to_quit; })) // timed out
{
std::cout << "Breaking RunThread Loop." << std::endl;
break;
}
else
{
std::cout << "TIMER CODE!" << std::endl;
}
the TIMER CODE usually shouldn't run within the std::mutex lock, as that means anyone sending a message is blocked until the timer code is finished.
}
}
Finally, WAKEUPs are spurious details. You could WAKEUP 50 times in that 5 seconds; condition variables do not guarantee a bounded number of checks.
asking_thread_to_quit = true;
cv.notify_all();
this again results in a race condition; your program does undefined behavior twice over now.
Changing asking_thread_to_quit to a std::atomic<bool> will get rid of the formal race condition and UB. It will, however, let your code miss a request to quit and mistakenly do another 5 second sleep followed by the task.
This is because the return value of your lambda could be calculated, then the asking_thread_to_quit=true and notify_all evaluates with nothing waiting on the condition variable (so nothing is woken up), then the condition variable is blocked on, 5 seconds pass, it wakes up returning false, then repeats the while loop.
With the mutex being held in all writes to the bool, the write cannot occur until after the lambda has returned and we are waiting on the condition with an unlocked mutex. This prevents the .notify_all() from being missed.
The cargo-cult solution to this is to always guard all reads and writes to asking_thread_to_quit by the cv_mutex. Then avoid holding the cv_mutex for any length of time, including while handling the timer wakeup.
std::unique_lock<std::mutex> lock_cv() {
return std::unique_lock<std::mutex>(cv_mutex);
}
void RunThread()
{
{
auto lock = lock_cv();
asking_thread_to_quit = false;
}
std::cout << "Started RunThread." << std::endl;
while(true)
{
{
auto lock = lock_cv();
using namespace std::literals::chrono_literals;
if(cv.wait_for(lock, 5s, [] { std::cout << "WAKEUP" << std::endl; return asking_thread_to_quit; })) // timed out
{
std::cout << "Breaking RunThread Loop." << std::endl;
break;
}
}
std::cout << "TIMER CODE!" << std::endl;
}
}
and in main:
{
auto lock = lock_cv();
asking_thread_to_quit = true;
}
cv.notify_all();
And yes, I intended for cv.notify_all() to be outside the mutex. It works; understanding why is outside the scope of the "cargo-cult" solution I'm providing here.
Finally, the WAKEUP is not spurious. The asking_thread_to_quit could have changed since the last time it was checked. Running the lambda guarantees we should fall asleep in a careful manner, with no gap between unlocking the mutex for waiting and waiting for notifications.
Spurious WAKEUPs can still occur; they would show up as more WAKEUPs than you expect.

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.

C++14 thread/condition variable misunderstanding

I'm trying to run a thread with a function from a class member and use conditional variable to wait until the main thread signals and add the times the thread got signaled. Here is the code:
// Example program
#include <iostream>
#include <string>
#include <atomic>
#include <thread>
#include <unistd.h>
#include <mutex>
#include <condition_variable>
std::mutex m_mutex;
std::condition_variable m_condVar;
char stop =0;
class dummclass
{
std::thread dummclass_thread;
int alarms;
public:
dummclass() :
alarms(0),
dummclass_thread(std::thread(&dummclass::dummclassThreadProc, this))
{
}
~dummclass()
{
std::cout<<"Alarms: "<<alarms<<"\n";
//signal thread before joining
{
std::lock_guard<std::mutex> lock_guard(m_mutex);
stop=1;
}
m_condVar.notify_one();
dummclass_thread.join();
}
private:
void dummclassThreadProc()
{
{
std::unique_lock<std::mutex> mlock(m_mutex);
std::cout<<"thread waiting\n";
m_condVar.wait(mlock);
std::cout<<"thread done waiting\n";
}
sleep(1);
std::unique_lock<std::mutex> mlock(m_mutex);
while (!stop)//!stop_dummclass.load())
{
std::cout<<"got mutex\n";
m_condVar.wait(mlock);
std::cout<<"wait done\n";
{
std::cout<<"got one\n";
alarms++;
}
}
std::cout<<"end loop\n";
}
};
int main()
{
dummclass *x = new dummclass;
sleep(3);
{
std::lock_guard<std::mutex> lock_guard(m_mutex);
}
m_condVar.notify_one();
std::cout<<"done waiting\n";
sleep(3);
for(int i=0;i<13;i++)
{
{
std::cout<<"signal "<<i<<"\n";
std::lock_guard<std::mutex> lock_guard(m_mutex);
}
m_condVar.notify_one();
}
delete x;
}
The weird part is that the initial waiting and signaling that are outside of the loops actually work ok. I don't understand what mistake I do so that the while loop inside the class thread doesn't catch any signal from the main thread but it catches a signal from the destructor of the dummyclass when I delete it. This is the output:
thread waiting
done waiting
thread done waiting
got mutex
signal 0 signal 1 signal 2 signal 3 signal 4 signal 5 signal 6 signal 7 signal
8 signal 9 signal 10 signal 11 signal 12
Alarms: 0
wait done
got one end loop
EDIT: It seems that adding a 1 second sleep in the main() for loop solves the problem. Is it possible that the for loop gets the mutex before wait() manages to wake and lock the mutex ?
for(int i=0;i<13;i++)
{
{std::cout<<"signal "<<i<<"\n";
std::lock_guard<std::mutex> lock_guard(m_mutex);}
m_condVar.notify_one();
sleep(1);
}
Can someone please show me what is wrong ?
Thanks.
The object doing the waiting gets deleted before it processes the signal. Since the delete happens on a known to be running thread it has a fair chance to get executed first. In particular it is also likely to reacquire the lock again: Since the notify_one() is done while the mutex is locked the wait()ing thread cannot acquire it and will go back to sleep, waiting for the mutex to be released. That gives the signalling thread an opportunity to reacquire the lock. The only forced synchronizqtion causing the signalling thread to wait is the join() and it does give the waiting thread a chance to execute.
Note that signals of condition variables are not something delivered to the waiting thread. They are essentially wake-up calls. The waiting thread will wake up eventually once a signal is delivered. However, many signals can be delivered before it actually does so.
I don't understand what mistake I do so that the while loop inside the
class thread doesn't catch any signal from the main thread
Even though multiple notifications are sent the thread may only receive a single notification.
The notify_one() call does
not mean that the current thread will stop and wait for another thread.
It just means that the other thread must wake up at some point because something may have happened that it would be interested in.
Also note that std::condition_variable::wait could experience a spurious wakeup, so it might not even have anything to do or have received a 'real' signal.
The solution is to provide a predicate as a parameter to the wait() call. The predicate can then check if there is a signal (via a variable provided for this purpose and only changed under lock) and may also check if the program has been stopped.
In the updated program below I've added a predicate to the wait and made some minor changes. The program only notifies under lock, but you might choose not to.
// Example program - modified
#include <iostream>
#include <string>
#include <atomic>
#include <thread>
//#include <unistd.h>
#include <mutex>
#include <condition_variable>
#include <chrono>
std::mutex m_mutex;
std::condition_variable m_condVar;
bool signal_waiting{false};
bool stop{false};
class dummclass
{
int alarms{};
std::thread dummclass_thread{[this](){dummclassThreadProc(); }};
public:
~dummclass()
{
std::cout << "Alarms: " << alarms << "\n";
//signal thread before joining
{
std::lock_guard<std::mutex> lock_guard(m_mutex);
stop = 1;
m_condVar.notify_one();
}
dummclass_thread.join();
}
private:
void dummclassThreadProc()
{
{
std::unique_lock<std::mutex> mlock(m_mutex);
std::cout << "thread waiting\n";
m_condVar.wait(mlock);
std::cout << "thread done waiting\n";
}
std::this_thread::sleep_for(std::chrono::seconds{1});
while(!stop)//!stop_dummclass.load())
{
std::unique_lock<std::mutex> mlock(m_mutex);
std::cout << "got mutex\n";
//m_condVar.wait(mlock);
m_condVar.wait(mlock, [](){return signal_waiting || stop; });
if(stop)
break;
std::cout << "wait done\n";
std::cout << "got one\n";
alarms++;
signal_waiting = false;
m_condVar.notify_one();
}
std::cout << "end loop\n";
}
};
int main()
{
dummclass *x = new dummclass;
//sleep(3);
std::this_thread::sleep_for(std::chrono::seconds{1});
{
std::lock_guard<std::mutex> lock_guard(m_mutex);
m_condVar.notify_one();
}
std::cout << "done waiting\n";
//sleep(3);
std::this_thread::sleep_for(std::chrono::seconds{1});
for(int i = 0; i<13; i++)
{
{
std::cout << "signal " << i << "\n";
std::unique_lock<std::mutex> lock(m_mutex);
m_condVar.wait(lock, [](){return !signal_waiting ; });
signal_waiting = true;
m_condVar.notify_one();
}
}
delete x;
}