In POSIX, why can't a single condvar be used with multiple mutexes?

Viewed 131

Why is the behavior undefined when a POSIX condition variable is used with multiple mutexes?

Excerpt from the 2018 edition:

When a thread waits on a condition variable, having specified a particular mutex to either the pthread_cond_timedwait() or the pthread_cond_wait() operation, a dynamic binding is formed between that mutex and condition variable that remains in effect as long as at least one thread is blocked on the condition variable. During this time, the effect of an attempt by any thread to wait on that condition variable using a different mutex is undefined

I suppose it's because of some kind of implementation detail of some specific system, so can someone confirm or refute it?

C11 (and C17) condition variables don't seem to have such limitation, and why?

3 Answers

C11 (and C17) condition variables don't seem to have such limitation,

I agree that C11 and C17 seem not to document any limitation on the mutex(es) used with cnd_wait or cnd_timedwait. However, they do permit these functions to fail, and one plausible reason they might fail is that a different mutex is specified than another thread currently waiting on the same CV specified.

and why?

I can only speculate about the standard committee's motivations and thought process. Possibly members wanted to allow implementations that do not have such a limitation, and they assumed that other implementations would simply exercise their option to fail as needed. Possibly it was simply an oversight.

It is both ordinary for condition variable implementations and appropriate for condition variable usage patterns to expect that multiple threads do not concurrently wait on a CV with different mutexes. POSIX is by no means unique in its restriction:

  • C++ std::condition_variable has a restriction analogous to POSIX's
  • Java objects' monitors and implementations of java.util.concurrent.locks.Condition are inherently associated with specific locks, so one cannot even express trying to use one with different locks at the same time.
  • Python threading.Condition objects are also associated with specific locks.

It is more of a "purpose" thing, std::mutex is more for a one thread signaling to many threads unlike std::atomic that works for most situations. The undefined part is probably trying to say "it may deadlock itself", it may happen anyways, but not because of the library. Some of the can't should be seen as a shouldn't, just test if ti works for you and thats it (mostly).

This answer is a logical one that "argues" me out of my confusion. Thanks goes to John Bollinger for inspiration.

Logically, a mutex, a condition variable object, and an abstract predicate are associated together, such that a wait operation on the condvar returns with the predicate changed compared to before the operation. In particular, the association between the mutex and the predicate is especially significant. This is consistent with the academically agreed on definition of a condition variable.

Logic: Suppose there are 2 threads waiting on a condvar with 2 different mutexes, logically this means that there are 2 independent predicates, thus, the 2 mutexes belong to different condition variables.

Implementation: Often, implementations of condition variables are user-space subroutines operating on kernel-backed semaphores, they are simplified and made more thread-safe when incorporating the above logical assumption.

Reality: What this means, is that signalling the change of 2 predicates using a single condvar is usually much less efficient and much more error-prone than signalling them using 2 different condvar.

Related