Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

condition_variable wait_for in 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"?

like image 674
lfybt Avatar asked Nov 20 '20 12:11

lfybt


People also ask

What is Condition_variable?

The condition_variable class is a synchronization primitive that can be used to block a thread, or multiple threads at the same time, until another thread both modifies a shared variable (the condition), and notifies the condition_variable . The thread that intends to modify the shared variable has to.

What is thread condition?

A condition variable allows one or more threads to wait until they are notified by another thread. If the lock argument is given and not None , it must be a Lock or RLock object, and it is used as the underlying lock. Otherwise, a new RLock object is created and used as the underlying lock.

What does Notify_all do?

The notify_all() member function unblocks all of the threads that are blocked on the specified condition variable at the time of the call. The order in which threads execute following a call to notify_all() is unspecified.

How do you use conditional variables?

Condition variables: used to wait for a particular condition to become true (e.g. characters in buffer). wait(condition, lock): release lock, put thread to sleep until condition is signaled; when thread wakes up again, re-acquire lock before returning.


1 Answers

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

  1. 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...

like image 93
Sam Varshavchik Avatar answered Oct 10 '22 09:10

Sam Varshavchik