17

Why it is required to lock a mutex before calling pthread_cond_wait?

Also, is it required to take a lock (on the same mutex) before calling pthread_cond_signal?

thanks for your help.

aajtak
  • 269
  • 1
  • 3
  • 8
  • 2
    See also: http://stackoverflow.com/questions/4544234/calling-pthread-cond-signal-without-locking-mutex – ninjalj Jun 10 '11 at 22:26

3 Answers3

26

Why it is required to lock a mutex before calling pthread_cond_wait?

Because otherwise there is an unavoidable race condition.

A mutex protects shared state. A condition variable is associated with some predicate ("condition") on the state. The basic idea is that you want to:

1) check the predicate

2) if the predicate is false, go to sleep until it becomes true

In a concurrent system, it is always possible for some thread to make the predicate true between (1) and (2). To avoid this race, you must hold a mutex before (1) and you must release it atomically as you perform (2).

For example, for a queue the predicate might be "the queue is not empty". But between the time you check to see if the queue is non-empty and the time you go to sleep, some other thread might add something to the queue.

Thus you must hold the mutex both while checking the predicate and at the time you call pthread_cond_wait.

Also, is it required to take a lock (on the same mutex) before calling pthread_cond_signal?

To my knowledge, there is no fundamental problem with this; it just introduces potential inefficiencies.

Here again, whatever shared state you are modifying (and thus making the predicate true) has to be protected by a mutex. So any time you want to signal the condition you must already hold the mutex anyway.

If you release the mutex before signaling the condition, it is possible for the predicate to become false in between due to the action of some other thread. This race does not cause failures because any thread waiting on the condition must double-check the predicate anyway before proceeding... But why put it through the trouble?

Bottom line: Just follow the instructions and you do not even have to think about these questions. :-)

Nemo
  • 70,042
  • 10
  • 116
  • 153
  • +1 for detailed answer. :-) I think requiring locking for signalling is to ensure memory consistency, since locking a mutex involves a memory barrier. Without it, other threads may not be able to observe the change. (Though, I guess it's possible to have the memory barrier _at_ signalling. But, it's probably simpler to require a lock.) – C. K. Young Jun 10 '11 at 21:49
  • 1
    @Chris: `pthread_cond_*()` is required by POSIX to synchronize memory: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_11 – ninjalj Jun 10 '11 at 22:05
  • 1
    @ninjalj @Chris: But POSIX also allows "spurious wakeups", so the waiter _must_ double-check the predicate anyway after receiving the signal. This really is academic, though. Almost anybody asking this sort of question probably should not be asking this sort of question :-). – Nemo Jun 10 '11 at 22:13
  • 1
    Also, the implementation is permitted to assume that there will not be concurrent calls to 'pthread_cond_wait' for the same condition variable (this may permit some optimizations). This is why all the threads waiting on a condition variable at the same time must pass the *same* mutex to 'pthread_cond_wait'. – David Schwartz Oct 26 '11 at 22:45
1

Condition variables are for synchronising on a condition that you are expecting to change. Locking ensures that:

  • The change can be reliably observed on the waiting threads
  • The item under change isn't somehow changed by another thread at the same time one of the now-woken-up threads is observing it

A condition system that doesn't use mutexes would be much more brittle.

C. K. Young
  • 219,335
  • 46
  • 382
  • 435
1

The whole point of condition variables is to allow threads to be notified of changes on data structures protected by a mutex, e.g. you may want to be notified when a queue is no longer empty, so you atomically release the mutex and wait on the condition variable, and when a new element is queued, you are awaken and take the mutex to process the new element.

Unlike Java's monitors, pthread_cond_{signal,broadcast}() doesn't need to hold the mutex. A signalling of a condition variable when no thread is waiting on that condition variable is lost, but that shouldn't make that much of a difference, since the signal could also be lost if the producer starts running before the consumer.

ninjalj
  • 42,493
  • 9
  • 106
  • 148