signal and unlock order
First, there is no correctness issue here. Either order will work. Recall that whenever you use condition variables, you must loop on a predicate while waiting:
pthread_mutex_lock(mutex);
while (!predicate)
pthread_cond_wait(cvar);
pthread_mutex_unlock(mutex);
By signalling after the unlock, you don't introduce any correctness issues; the thread is still guaranteed to wake up, and the worst case is another wakeup comes first - at which point it sees the predicate becomes true and proceeds.
However, there are two possible performance issues that can come up.
- "Hurry up and wait". Basically, if you signal while the lock is held, the other thread still needs to wait until the mutex is available. Many pthreads implementations will, instead of waking up the other thread, simply move it to the wait queue of the mutex, saving an unnecessary wakeup->wait cycle. In some cases, however this is unimplemented or unavailable, leading to a potential spurious context switch or IPI.
Spurious wakeups. If you signal after the unlock, it's possible for another thread to issue another wakeup. Consider the following scenario:
- Thread A starts waiting for items to be added to a threadsafe queue.
- Thread B inserts an item on the queue. After unlocking the queue, but before it issues the signal, a context switch occurs.
- Thread C inserts an item on the queue, and issues the cvar signal.
- Thread A wakes up, and processes both items. It then goes back to waiting on the queue.
- Thread B resumes, and signals the cvar.
- Thread A wakes up, then immediately goes back to sleep, because the queue is empty.
As you can see, this can introduce a spurious wakeup, which might waste some CPU time.
Personally, I don't think it's worth worrying too much about it either way. You don't often know offhand whether your implementation supports moving waiters from the condition variable to the mutex wait queue, which is the only real criterion you could use to decide which to use.
My gut feeling would be that, if I had to choose, signalling after the unlock is marginally less likely to introduce an inefficiency, as the inefficiency requires a three-thread race, rather than a two-thread race for the "hurry up and wait" condition. However, this is not really worth worrying about, unless benchmarks show too much context switch overhead or something.
Calling pthread_cond_signal without locking mutex
If you do not lock the mutex in the codepath that changes the condition and signals, you can lose wakeups. Consider this pair of processes:
Process A:
pthread_mutex_lock(&mutex);
while (condition == FALSE)
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
Process B (incorrect):
condition = TRUE;
pthread_cond_signal(&cond);
Then consider this possible interleaving of instructions, where condition
starts out as FALSE
:
Process A Process B
pthread_mutex_lock(&mutex);
while (condition == FALSE)
condition = TRUE;
pthread_cond_signal(&cond);
pthread_cond_wait(&cond, &mutex);
The condition
is now TRUE
, but Process A is stuck waiting on the condition variable - it missed the wakeup signal. If we alter Process B to lock the mutex:
Process B (correct):
pthread_mutex_lock(&mutex);
condition = TRUE;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
...then the above cannot occur; the wakeup will never be missed.
(Note that you can actually move the pthread_cond_signal()
itself after the pthread_mutex_unlock()
, but this can result in less optimal scheduling of threads, and you've necessarily locked the mutex already in this code path due to changing the condition itself).
unlock the mutex after condition_variable::notify_all() or before?
There are no advantages to unlocking the mutex before signaling the condition variable unless your implementation is unusual. There are two disadvantages to unlocking before signaling:
If you unlock before you signal, the signal may wake a thread that choose to block on the condition variable after you unlocked. This can lead to a deadlock if you use the same condition variable to signal more than one logical condition. This kind of bug is hard to create, hard to diagnose, and hard to understand. It is trivially avoided by always signaling before unlocking. This ensures that the change of shared state and the signal are an atomic operation and that race conditions and deadlocks are impossible.
There is a performance penalty for unlocking before signaling that is avoided by unlocking after signaling. If you signal before you unlock, a good implementation will know that your signal cannot possibly render any thread ready-to-run because the mutex is held by the calling thread and any thread affects by the condition variable necessarily cannot make forward progress without the mutex. This permits a significant optimization (often called "wait morphing") that is not possible if you unlock first.
So signal while holding the lock unless you have some unusual reason to do otherwise.
Must lock be held when signaling conditional variable?
For normal usage, you can unlock the mutex before signalling a condition variable.
The mutex protects the shared state (in this case the should_wake_up
flag). Provided the mutex is locked when modifying the shared state, and when checking the shared state, pthread_cond_signal
can be called without the mutex locked and everything will work as expected.
Under most circumstances, I would recommend calling pthread_cond_signal
after calling pthread_mutex_unlock
as a slight performance improvement. If you call pthread_cond_signal
before pthread_mutex_unlock
then the waiting thread can be woken by the signal before the mutex is unlocked, so the waiting thread then has to go back to sleep, as it blocks on the mutex that is still held by the signalling thread.
What happens to a thread calling pthread_cond_signal?
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 Topics
Why Does Rand() Return the Same Value Using Srand(Time(Null)) in This for Loop
Unary Plus (+) Against Literal String
How to Check Deallocation of Memory
Is Static Init Thread-Safe with Vc2010
Is 'Volatile' Needed in This Multi-Threaded C++ Code
How to Treat a Specific Warning as an Error
How to Print the Address of Char Array
How to Set Given Channel of a Cv::Mat to a Given Value Efficiently Without Changing Other Channels
Throwing the Fattest People Off of an Overloaded Airplane
What's the Best Hashing Algorithm to Use on a Stl String When Using Hash_Map
Is a Struct's Address the Same as Its First Member's Address
If a 32-Bit Integer Overflows, How to Use a 40-Bit Structure Instead of a 64-Bit Long One
How to Copy Std::String into Std::Vector<Char>
C++: Difference Between Member and Non Member Functions
How to Convert Concatenated Strings to Wide-Char with the C Preprocessor