Firstly, there is no problem with correctness. Any order will work. Recall that whenever you use condition variables, you must loop around the predicate while waiting:
pthread_mutex_lock(mutex); while (!predicate) pthread_cond_wait(cvar); pthread_mutex_unlock(mutex);
With a signal after unlocking, you do not enter any problems with the correctness; the flow is still guaranteed to wake up, and in the worst case, another awakening occurs - at this moment he sees that the predicate becomes true and continues.
However, two performance issues are possible:
- "Hurry up and wait." Basically, if you signal that the lock is being held, the other thread should still wait until the mutexes are available. Many pthreads implementations, instead of waking up another thread, simply transfer it to the mutex wait queue, preserving an unnecessary wait loop → wait. In some cases, however, this is not implemented or not available, resulting in a potential false context switch or IPI.
Fake Awakenings. If you signal after unlocking, it is possible that another thread will issue another wake up. Consider the following scenario:
- In thread A, the wait begins for items to be added to the thread queue.
- Thread B inserts the item into the queue. After the queue is unlocked, but before it issues a signal, a context switch appears.
- Thread C inserts the element into the queue and issues a cvar signal.
- Thread A wakes up and processes both elements. Then he returns to waiting in line.
- Thread B resumes and signals cvar.
- Thread A wakes up and then immediately goes back to sleep because the queue is empty.
As you can see, this can lead to a false awakening, which can lead to the cancellation of some processor time.
Personally, I don’t think it bothered too much about it. You do not often know, regardless of whether your implementation supports the transfer of waiters from a condition variable to the mutex wait queue, which is the only real criterion that you can use to decide what to use.
My gut feeling would be that if I had to choose, an alarm after unlocking would be less likely to introduce inefficiency, since inefficiency requires a three-threaded race, and not a two-threaded race for up and wait rush. However, actually it’s not worth worrying if the tests have too much redundant context switching or something else.
bdonlan Jun 21 2018-11-11T00: 00Z
source share