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);
Related
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.
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.
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.
Imagine I have a mutex locked. There is unlimited number of other threads waiting to lock the mutex. When I unlock the mutex, one of those threads will be chosen to enter the critical section. However I have no control over which one. What if I want specific thread to enter the critical section?
I am prety sure this cannot be done using POSIX mutex, however, can I emulate the behaviour using different synchronisation object(s)?
You can use a mutex, a condition variable and a thread id to achive that.
Before unlocking the mutex the thread sets the target thread id, broadcasts the condition variable and releases the mutex. The waiting threads wake up, lock the mutex and check whether the target thread id equals to this thread id. If not the thread goes back to wait.
An optimization to this method to avoid waking up all waiting threads just to check the target thread id and then go back to wait would be to use a separate condition variable for each waiting thread. This way the signaling thread would notify the condition variable of the particular target thread.
Another option is to use signals sent to a particular thread. Let's say we use SIGRTMINfor this purpose. First, all threads block this signal at the start, so that the signal becomes pending and doesn't get lost when the thread isn't waiting for it. When a thread wants to lock the mutex it first calls sigwait() which atomically unblocks SIGRTMIN and waits for it or delivers an already pending one. Once the thread received the signal it can proceed and lock the mutex. The signaling thread uses pthread_kill(target_thread_id, SIGRTMIN) to wake up a particular thread.
Singularity - If a thread managed to lock a mutex, it is assured that no other thread will be able to lock the thread until the original thread releases the lock.
Non-Busy Wait - If a thread attempts to lock a thread that was locked by a second thread, the first thread will be suspended (and will not consume any CPU resources) until the lock is freed by the second thread. At this time, the first thread will wake up and continue execution, having the mutex locked by it.
From: Multi-Threaded Programming With POSIX Threads
Question: I thought threads lock the mutex variables. Threads don't lock other threads?
What do the bold statements above mean? How can one thread lock other thread?
Corrections:
If a thread managed to lock a mutex, it is assured that no other thread will be able to lock the mutex until the original thread releases the lock.
Non-Busy Wait - If a thread attempts to lock a mutex that was locked by a second thread, the first thread will be suspended (and will not consume any CPU resources) until the lock is freed by the second thread. At this time, the first thread will wake up and continue execution, having the mutex locked by it.
It's a good thing you don't take for granted whatever you read on the internet, also I give you thumbs up for paying attention to what you read.