std::condition_variable::notify_one() called several times without context switching - c++

How many waiting threads will wake up in this example:
1st thread:
void wakeUp2Threads()
{
std::unique_lock<std::mutex> lock(condvar_mutex);
condvar.notify_one();
condvar.notify_one();
}
2nd thread:
{
std::unique_lock<std::mutex> lock(condvar_mutex);
condvar.wait(lock); <- 2nd thread has entered here before 1st thread entered wakeUp2Threads.
}
3rd thread (the same as 2nd):
{
std::unique_lock<std::mutex> lock(condvar_mutex);
condvar.wait(lock); <- 3rd thread has entered here before 1st thread entered wakeUp2Threads.
}
Is there any guarantee that in this example both notifications will be delivered to different threads, not the same thread several times?
I.e what does notify_one() mean:
1) notify one thread, no matter has it been already notified (but has not been woken up yet), or not. (* see note)
or
2) notify one thread, but only this one, which has not been notified yet.
(*) Pay attention! I'm not talking here about scenario "waiting thread had already been notified somewhere in the past, woken up, done some stuff and entered condvar.wait() again" - of course, in this case several notify_one() routines can wake up the same thread over and over again.
I'm talking about another case:
notify_one() has notified waiting thread about wake-up, but BEFORE this waiting thread has received time slot form the kernel scheduler and continued execution - another notify_one() has been called again. Is it possible this second notification will be delivered to the same thread again, while it hasn't been woken up from first notification yet?

The notify_one call atomically unblocks one thread. That means that when called a second time it can't unblock the same thread as it's no longer blocked.
This is specified in the standard at section 30.5/3 and 30.5.1/7.

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.

Will consumer thread receive condition_variable notify signal if spuriously woken up

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

Interruptible thread example in 《C++ Concurrency In Action》

《C++ Concurrency In Action》 implements an interruptible thread in Chapter 9.2 Interrupting thread. Listing 9.10 is below:
void interruptible_wait(std::condition_variable& cv,
std::unique_lock<std::mutex>& lk)
{
interruption_point();
this_thread_interrupt_flag.set_condition_variable(cv);
cv.wait(lk);
this_thread_interrupt_flag.clear_condition_variable();
interruption_point();
}
According to the book, this function introduces the problem below:
If the thread is interrupted after the initial call to interruption_point(), but before the call to wait(), then it doesn’t matter whether the condition variable has been associated with the interrupt flag, because the thread isn’t waiting and so can’t be woken by a notify on the condition variable. You need to ensure that the thread can’t be notified between the last check for interruption and the call to wait().
The first question is why we need to ensure that? 'Cause this function seems to run correctly even the thread is interrupted after the initial call to interruption_point() and before the call to wait(). Could anyone tell me how this function will go south? Is it because cv.wait(lk) will never be notified under this situation?
The second question is how Listing 9.11 solve this problem the book mentions just by replacing cv.wait() by cv.wait_for():
void interruptible_wait(std::condition_variable& cv,
std::unique_lock<std::mutex>& lk)
{
interruption_point();
this_thread_interrupt_flag.set_condition_variable(cv);
interrupt_flag::clear_cv_on_destruct guard;
interruption_point();
cv.wait_for(lk,std::chrono::milliseconds(1));
interruption_point();
}
If the other thread calls notify() before this thread gets to wait(), this thread won't receive that notification, and will wait forever for another one.
wait_for doesn't wait forever.

java.lang.Object notify() - does it notify a thread at random, or the first one to call wait()?

Say I have 3 threads (A, B, and C) that are waiting for the monitor on an object O. Thread D currently has the monitor for Object O. When thread D calls O.notify, which thread gets notified first? A, B, or C? Is it based off the first of those threads to call wait() on object O? Perhaps I am speaking about the difference between notify() and notifyAll()? If I were to guess, notify() would notify the first thread to call wait() and notifyAll() would notify all threads that called wait() AND the next thread to get the monitor would basically be at random?
It's any thread which is waiting on the monitor. From section 17.2.2 of the JLS:
There is no guarantee about which thread in the wait set is selected. This removal from the wait set enables u's resumption in a wait action. Notice, however, that u's lock actions upon resumption cannot succeed until some time after t fully unlocks the monitor for m.
And from the Object.notify docs:
Wakes up a single thread that is waiting on this object's monitor. If any threads are waiting on this object, one of them is chosen to be awakened. The choice is arbitrary and occurs at the discretion of the implementation. A thread waits on an object's monitor by calling one of the wait methods.

std::condition_variable::notify_one() called twice [duplicate]

This question already has an answer here:
std::condition_variable::notify_one() called several times without context switching
(1 answer)
Closed 10 years ago.
How many waiting threads will wake up if I call std::condition_variable::notify_one() twice without any time interval, like this:
{
std::unique_lock<std::mutex> lock(condvar_mutex);
condvar.notify_one();
condvar.notify_one();
}
Is there any guarantee that these notifications will be delivered to different threads, not the same thread several times?
§30.5.1.7: If any threads are blocked waiting for *this, unblocks one
of those threads.
There is no guarantee that it's different threads, just that it's one thread. During the time between the two notify_one calls it is possible that the same thread that was waked with the first notify_one is re-blocked.
e.g. In the following example it is not guaranteed whether thread 3 will wake or not (disregard spurious wakes for this example).
- thread 1:
1 condvar.notify_one();
- 3 and 4 could run here.
2 condvar.notify_one();
- thread 2:
3 condvar.wait(/*...*/);
4 condvar.wait(/*...*/);
- thread 3:
5 condvar.wait(/*...*/);
I assume that condvar_mutex is the correct mutex for the condvar.
It's not possible for both notifications to be delivered to the same thread. The reason is that you call notify_one twice while holding the mutex. So whichever thread is unblocked first, there's no way it can acquire the mutex, so it can't return from wait. It can't even throw an exception from wait_for without first acquiring the mutex.
Since it can't get out of its wait, there's no way it can get back onto the list of waiters before the second notify_one is called.
So, your code unblocks up to two threads blocked on the condvar, if there are that many. If there are fewer then the additional notifications have no effect.