missed signal in c++11 condition variable - multithreading

I have a small doubt about thread being woken up and unavailability of the lock
std::mutex mut;
std::queue<data_chunk> data_queue;
std::condition_variable data_cond;
void data_preparation_thread() {
while(more_data_to_prepare()) {
data_chunk const data=prepare_data();
std::lock_guard<std::mutex> lk(mut);
data_queue.push(data);
data_cond.notify_one(); //mutex is still locked here
}
}
void data_processing_thread() {
while(true) {
std::unique_lock<std::mutex> lk(mut);
data_cond.wait(lk,[]{return !data_queue.empty();}); //what if lk could not acquire the mutex.
data_chunk data=data_queue.front();
data_queue.pop();
lk.unlock();
process(data);
if(is_last_chunk(data))
break;
}
}
In the above example data_preparation_thread() puts data in the queue and notifies and thread waiting on the condition_variable.
My question, if the other thread wakes up and finds the associated mutex is still not available, it sleeps again. Isn't it a condition of missed signal ?

if the other thread wakes up and finds the associated mutex is still not available, it sleeps again
Once it re-acquires the mutex it proceeds to test the condition.
Condition variable notification is essentially a hint that the condition may have changed and needs to be re-evaluated. There can be spurious wake-ups. The code waits for the condition to become true, not for the signal.

There's a difference between "sleeping" on the condition variable (i.e. waiting for a signal) and "sleeping" on the mutex (i.e. waiting to lock it).
If the thread wakes up from waiting on the condition variable and the mutex is still locked it starts waiting on the mutex, until it can acquire it and then check the condition (i.e. the predicate). That's not the same as waiting on the condvar again, so nothing has been missed. It's still waiting to check if the condition is true, which it can't do until it acquires the mutex lock.
Assuming that you correctly check the condition when waking (which is what the predicate you pass to condition_variable::wait does) then you won't miss the event that caused the signal.

Related

What happens to a thread calling pthread_cond_signal?

When a thread calls pthread_cond_signal, one of the threads waiting on the condition will resume its execution. But what happens to the calling thread? Does it waits for the called thread to release the mutex and then it resumes?
For example, the waiting thread:
pthread_mutex_lock(&mut);
// ...
pthread_cond_wait(&cond, &mut);
// ...
pthread_mutex_unlock(&mut);
And the signaling thread:
pthread_mutex_lock(&mut);
// ...
pthread_cond_signal(&cond);
// ... has work to finish
pthread_mutex_unlock(&mut);
In this case, how can the signaling thread continue its work if the waiting thread has taken over the mutex?
The thread that calls pthread_cond_signal returns immediately. It does not wait for the woken thread (if there is one) to do anything.
If you call pthread_cond_signal while holding the mutex that the blocked thread is using with pthread_cond_wait, then the blocked thread will potentially wake from the condition variable wait, then immediately block waiting for the mutex to be acquired, since the signalling thread still holds the lock.
For the best performance, you should unlock the mutex prior to calling pthread_cond_signal.
Also, pthread_cond_wait may return even though no thread has signalled the condition variable. This is called a "spurious wake". You typically need to use pthread_cond_wait in a loop:
pthread_mutex_lock(&mut);
while(!ready){
pthread_cond_wait(&cond,&mut);
}
// do stuff
pthread_mutex_unlock(&mut);
The signalling thread then sets the flag before signalling:
pthread_mutex_lock(&mut);
ready=1
pthread_mutex_unlock(&mut);
pthread_cond_signal(&cond);

pthread join child thread in both thread function and cancellation handler?

I got the following scenario with a concurrency problem, implemented using pthread library:
I got a thread that might be cancelled at any time. When that thread is cancelled, it needs to cancel its child thread, and make sure its child thread is already cancelled before it terminates.
So I end up with calling pthread_join twice on the child thread, once in the thread routine (as when the thread is not cancelled, I need that result), once in the thread's cancellation cleanup handler.
However, pthread_join doesn't allow joining the same thread twice, so what will happen?
Below is pseudo code:
void CleanupFunc(void* ChildThread)
{
pthread_cancel(*(pthread_t*)ChildThread);
pthread_join(*(pthread_t*)ChildThread, NULL);
}
void* ThreadFunc(void* _)
{
pthread_t ChildThread;
pthread_cleanup_push(&CleanupFunc, &ChildThread);
pthread_create(&ChildThread, NULL, &ChildThreadFunc, NULL);
pthread_join(ChildThread, NULL);
pthread_cleanup_pop(0);
}
Thanks in advance!
However, pthread_join doesn't allow joining the same thread twice, so what will happen?
The thread is no longer joinable, so the result is undefined behavior.
Per the POSIX standard documentation for pthread_join():
The behavior is undefined if the value specified by the thread
argument to pthread_join() does not refer to a joinable thread.

Condvar behaviour after signal, but before mutex release

I am trying to understand what guarantees I have just after I signalled a condvar.
The basic pattern of usage is, I believe, this (pseudocode):
Consumer Thread:
Mutex.Enter()
while(variable != ready)
Condvar.Wait()
Mutex.Exit()
Producer Thread:
Mutex.Enter()
variable = ready
Condvar.Broadcast()
[Unknown?]
Mutext.Exit()
My question is. What am I guaranteed about the [Unknown] point in the code above? I am still holding the mutex, but what can I know about the state of the consumer?
From the Man page, it is unclear to me what state the producer is in after it broadcasts/signals and before it releases the mutex.
From condition vars:
pthread_cond_wait() blocks the calling thread until the specified condition is signalled. This routine should be called while mutex is locked, and it will automatically release the mutex while it waits. After signal is received and thread is awakened, mutex will be automatically locked for use by the thread. The programmer is then responsible for unlocking mutex when the thread is finished with it.
So, when producer is executing the Unknown section of code, producer is holding the mutex, and the consumer is locked on the mutex until producer releases it.

Is a thread holding the respective mutex on a spurious wakeup?

Let's take a look at the code below.
Suppose a thread sees ready=false and therefore waits on the condition variable *mv_cv*, hence releasing the mutex *my_mutex* and putting itself to sleep.
Some time later, something spuriously wakes the thread up while ready still holds the value false. My question is:
Is the thread now holding the mutex *my_mutex* by reacquiring the mutex before waking up?
pthread_mutex_lock(&my_mutex);
while ( !ready )
{
pthread_cond_wait(&my_cv, &my_mutex);
}
//some operation goes here
pthread_mutex_unlock(&my_mutex);
Yes. Spurious wake-up is one kind of successful return, and post condition (reacquiring lock of the mutex) will be fulfilled.

Multile pthread_cond_wait waken up and hold the mutex lock

According to the man page, pthread_cond_broadcast wakes up all the threads that are waiting on condition variable (condvar). And those waken threads will hold back the mutex lock and return from pthread_cond_wait.
But what I am confusing is: Isn't it the mutex lock should held by only one thread in the same time?
Thanks in advance.
Condition variables work like this:
/* Lock a mutex. */
pthread_mutex_lock(&mtx);
/* Wait on condition variable. */
while (/* condition *.)
pthread_cond_wait(&cond, &mtx);
/* When pthread_cond_wait returns mtx is atomically locked. */
/* ... */
/* Unlock the mutex. */
pthread_mutex_unlock(&mtx);
So the main point to understand is that many threads can wake up when a broadcast is sent, but only one will "win" the race and actually lock mtx and get out of the loop.

Resources