Reputation: 123
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"?
Upvotes: 12
Views: 6856
Reputation: 9485
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;
}
}
}
Upvotes: 0
Reputation: 118435
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...
Upvotes: 13