Will consumer thread receive condition_variable notify signal if spuriously woken up - c++

We know that condition variables a subject to spurious wake ups. Let's assume we have a 1-producer-1-consumer queue synchronized with a mutex and condition variable. The consumer thread gets a spurious wake up.
The question is - will the consumer thread miss the notify signal from the producer?
I understand it's extremely unlikely.. but is it still possible to lose the last element in the queue with such implementation?

If the code that calls wait() isn't written right, it could, indeed, miss a wake up. But that would be a bit perverse. The usual idiom is:
lock the mutex
while the condition is not satisfied
wait on the condition variable
the signaling thread should lock the mutex before signaling:
lock the mutex
signal the condition variable
Waiting on the condition variable unlocks the mutex for the duration of the wait. When the wait call returns, though, the mutex will be locked. So on a spurious wake up, the waiting thread will hold the mutex until it resumes waiting. While the waiting thread holds the mutex, the signaling thread can't signal the condition variable. When the waiting thread actually waits, the mutex gets unlocked and the signaling thread can go ahead and signal; the waiting thread will get the signal, and once the signaling thread releases the mutex, the waiting thread will resume execution.
So, no, proper code won't miss a signal. But if the waiting thread releases the mutex and reacquires it in the course of checking its condition, the signal could occur before the waiting thread calls wait, and the signal will be lost. Don't do that. <g>

Spurious wake up means it might wake up spuriously and then have to continue waiting.
It does not refer at all to the possibility of missing an event, for it would be useless if that were true.
This link provides a detailed explanation of cv and the wait method:
https://www.codeproject.com/Articles/598695/Cplusplus-threads-locks-and-condition-variables
// print a starting message
{
std::unique_lock<std::mutex> locker(g_lockprint);
std::cout << "[logger]\trunning..." << std::endl;
}
// loop until end is signaled
while(!g_done)
{
std::unique_lock<std::mutex> locker(g_lockqueue);
g_queuecheck.wait(locker, [&](){return !g_codes.empty();});
// if there are error codes in the queue process them
while(!g_codes.empty())
{
std::unique_lock<std::mutex> locker(g_lockprint);
std::cout << "[logger]\tprocessing error: " << g_codes.front() << std::endl;
g_codes.pop();
}
}

Related

c++11 std::notify_all and spurious wakeup

with c++11.
As std::notify_all would cause spurious wakeup, then why std::notify_all is remained but not std::notify_one all the time?
And could std::notify_one cause spurious wakeup by the way?
elaborating my doubts:
When I call std::condition_variable.wait/wait_for/wait_until and std::notify_XXX, my purpose is generally to implement thread sychronisation. That is to say, more threads blocked to wait until another thread to notify only one of them to unblock.
Then I can just call notify_one to achieve that, but why there's another notify_all, what is its purpose, or what situation is notify_all suitable for?
And in my situation, when I call notify_all, it will wakeup all waiting threads, then only one thread actually unblock and others remains blocking, is it called spurious wakeup?
And if notify_one would call spurious wakeup as well?
On void std::condition_variable::wait(std::unique_lock<std::mutex>& lock); from
thread.condition/8.3:
The function will unblock when signaled by a call to notify_­one() or a call to notify_­all(), or spuriously.
So calling notify_­one() or notify_­all() is not a prerequisite. It can unblock without any of those being called.
The above quote is from "C++20 first post-publication draft" but has remained the same since it was first written for C++11.
why there's another notify_all, what is its purpose, or what situation is notify_all suitable for?
When you want all waiting threads to unblock. A practical situation would be when it's time to shutdown. If you have threads blocked in a wait they will never finish and join()ing them will hang.
Example with a predicate saying that it should wait until either aborted is true or queue.empty() is false:
bool pop_from_queue(T& item) {
std::unique_lock<std::mutex> lock(mtx);
while(queue.empty() && not aborted) cv.wait(lock);
if(aborted) return false; // time to shutdown
// else pick an item from the queue
item = std::move(queue.front());
queue.pop();
return true;
}
When it's time to shutdown, another thread would here typically do:
aborted = true; // std::atomic<bool>
cv.notify_all();
when I call nitify_all, it will wakeup all waiting threads, then only one thread actually unblock and others remains blocking, is it called spurious wakeup?
No. A spurious wakeup is a wakeup that can happen at any time. If you call notify_all, the waiting threads will all wakeup as ordered - not spuriously.
And if notify_one would call spurious wakeup as well?
It may cause a spurious wakeup, but that would be an implementation detail. The best thing is to just live with the fact that the threads may wakeup at any time and just check the predicate when they do.
could I precislly control where to unblock in the waiting thread(who called condition_variable.wait with no Predicate)?
Without checking the predicate, the only thing the thread knows for sure is that it woke up. It does not now if it's for the right reason or not.

Condition variable waiting on multiple mutexes

I have a std::condition_variable_any that waits on a custom lock which is a composition of two mutexes (one std::mutex and one shared-locked std::shared_mutex). Its unlock() operation simply unlocks both mutexes sequentially.
For example (pseudocode):
mutex mutex1;
shared_mutex mutex2;
condition_variable_any cv;
// acquiring the locks
DualLock lock(unique_lock(mutex1), shared_lock(mutex2));
// waiting
cv.wait(lock);
cv.wait() should atomically unlock both mutex1 and mutex2, and put the thread to sleep until cv gets notified.
It it still guaranteed that the thread is sleeping and listening to the condition variable notification, once any of mutex1 or mutex2 is unlocked?
Or is it possible that one mutex gets unlocked, and a second thread locks it, sends the notification, but this first thread was not yet sleeping and listening. So the notification never arrived and no wakeup occurs.
If DualLock meets the requirements of BasicLockable, then the code will perform as hoped. If not, it won't.
BasicLockable reference is here
So the notification never arrived and no wakeup occurs.
This can never happen when condition variables are used properly. The wakeup of a condition variable cannot be interpreted as a signal of an event, since the documentation of condition_variable explains that there can be spurious wakeups.
At best, the notification is an indication that now may be a good time to test the condition you're waiting for (and you may do so in the secure knowledge that the test is protected by the mutex).
The state of the condition and the state of the blocked-ness of the current thread are two separate concerns.
Here's a better example (assumes that DualLock models BasicLockable correctly):
bool condition_met = false;
mutex mutex1;
shared_mutex mutex2;
condition_variable_any cv;
// acquiring the locks
DualLock lock(unique_lock(mutex1), shared_lock(mutex2));
while(!condition_met)
{
// waiting
cv.wait(lock);
}
// whatever happens, you have the lock here
// ...work
lock.unlock();
Your notifier would notify this way:
DualLock lock(unique_lock(mutex1), shared_lock(mutex2));
condition_met = true;
lock.unlock(); // note the order: unlock mutex first...
cv.notify_all(); // ...then notify the condition variable

C++: Is the passing of a mutex from a notifier to a waiter seamless?

In a multithreaded environment, we have the following two functions:
std::mutex mtx;
std::condition_variable cv;
void waiter()
{
std::unique_lock<std::mutex> lck(mtx);
//...
cv.wait(lck);
//...
}
void notifier()
{
std::unique_lock<std::mutex> lck(mtx);
//...
cv.notify_one();
}
Assume that the waiter executes first and then waits on the condition_variable. Then the notifier executes and notifies the waiter. The waiter tries to reacquire the mutex after the notifier has released it.
Question: Is it possible that some other thread locks the mutex right after the notifier has released it but still before the waiter gets it? If yes, what has to be done so that this cannot happen? And if yes, I also don't understand the purpose of condition_variable. The purpose should be to block a thread until some condition is fulfilled. But if, after the condition is fulfilled and the thread has been woken up, there is the chance that again the condition is not fulfilled, what's the point?
Is it possible that some other thread locks the mutex right after the notifier has released it but still before the waiter gets it?
Yes.
If yes, what has to be done so that this cannot happen?
Nothing.
And if yes, I also don't understand the purpose of condition_variable. The purpose should be to block a thread until some condition is fulfilled. But if, after the condition is fulfilled and the thread has been woken up, there is the chance that again the condition is not fulfilled, what's the point?
It's even more complicated. The thread can be woken up if the condition variable was not notified at all. This is called spurious wakeup (doc).
The point of condition variable is to block a thread until some other thread notifies it. In order to address the "condition is not fulfilled when the waiting thread gets a chance to execute" issue usually the waiting thread waits in a loop until the condition is fulfilled. The standard library even has a shortcut for that, there is a void wait( std::unique_lock<std::mutex>& lock, Predicate pred ); overload that does exactly that. See the doc.

Understanding std::condition_variables

I'm trying to understand the flow of the condition_variable when I have more than one thread waiting to execute. To my understanding, all threads would try to grab the unique lock, one would get it and then progress to the wait(), if you call notify_all, wouldn't there at most be one thread waiting that would be allowed through. Until it releases it's lock and allows the other threads through.
Does the cv communicate with the unique lock and let all threads through all at once? If so is it truly all at once or do the threads sequentially pass through one after another.
std::condition_variable cv;
std::mutex cv_m; // This mutex is used for three purposes:
// 1) to synchronize accesses to i
// 2) to synchronize accesses to std::cerr
// 3) for the condition variable cv
int i = 0;
void waits()
{
std::unique_lock<std::mutex> lk(cv_m);
std::cerr << "Waiting... \n";
cv.wait(lk, []{return i == 1;});
std::cerr << "...finished waiting. i == 1\n";
}
http://en.cppreference.com/w/cpp/thread/condition_variable/notify_all
When you call wait (the one-argument version) the lock is unlocked and the thread enter a wait-state until the CV is "notified". When a thread wakes up the lock is locked again.
When you call notify_one, basically a random thread waiting on the CV will be notified. When you call notify_all all threads waiting on the CV will be woken up from the wait-state, and the first that locks the lock will be the one that continues. Which that will be is also random.
Note that when I say "random", the actual implementation of threads (from the C++ library down to the operating system kernel and maybe even the hardware) on your system may be implemented in a way to make it possible to infer which thread will be the one that wakes up and gets the lock, but from the point of view of us application writers who uses condition variables, there's no predetermined order, it's random.
While the threads do have to call wait one at a time, while they're waiting, they don't hold the lock. So additional threads can get through to the wait function.

Condition variable deadlock

I have a problem with a deadlock in my code related to the use of condition variables. This is more of a design question than a pure code question. I have no problem actually writing code once I understand the correct design. I have the following scenario:
Thread A waits on a condition variable.
Thread B calls notify_all, and thread A wakes up.
This is of course what I want to happen, and is what does happen when everything works as expected. But sometimes, I get the following scenario instead:
Thread A executes the code right before it begins to wait on the condition variable.
Thread B calls notify_all, thinking that thread A is waiting.
Thread A begins waiting on the condition variable, not realizing that thread B already told it to stop waiting. Deadlock.
What is the best way to resolve this? I can't think of a reliable way to check whether thread A is actually waiting, in order to know when I should call notify_all in thread B. Do I have to resort to timed_lock? I would hate to.
During the period just before Thread A waits on condition variable it must be holding a mutex. The easiest solution is to make sure that Thread B is holding the same mutex at the time it calls notify_all. So something like this:
std::mutex m;
std::condition_variable cv;
int the_condition = 0;
Thread A: {
std::unique_lock<std::mutex> lock(m);
do something
while (the_condition == 0) {
cv.wait(lock);
}
now the_condition != 0 and thread A has the mutex
do something else
} // releases the mutex;
Thread B: {
std::unique_lock<std::mutex> lock(m);
do something that makes the_condition != 0
cv.notify_all();
} // releases the mutex
This guarantees that Thread B only does the notify_all() either before Thread A acquires the mutex or while Thread A is waiting on the condition variable.
The other key here, though, is the while loop waiting for the_condition to become true. Once A has the mutex it should not be possible for any other thread to change the_condition until A has tested the_condition, found it false, and started waiting (thus releasing the mutex).
The point is: what you are really waiting for is for the value of the_condition to become non-zero, the std::condition_variable::notify_all is just telling you that thread B thinks thread A should wake up and retest.
A condition variable must always be associated with a mutex to avoid a race condition created by one thread preparing to wait and another thread which may signal the condition before the first thread actually waits on it resulting in a deadlock. The thread will be perpetually waiting for a signal that is never sent. Any mutex can be used, there is no explicit link between the mutex and the condition variable.