cnd_t
functionsAuthors: Jens Gustedt
Date: 2025-06-24
Submitted against: C23
Status: Open
The timing and synchronization of calls to cnd_t
functions are
underspecified. In particular the text for cnd_broadcast
and
cnd_signal
talk about
... threads that are blocked on the condition variable pointed to by
cond
at the time of the call
Fortunately, this lack of precision has not yet resulted in severe
misunderstandings or even bugs. Nevertheless, it has merely pushed
implementors to go on the safe side, perhaps imposing too much
synchronization constraints on calls to cnd_t
functions. For
example, it seems that many implementations regulate the access to
cnd_t
variables through an internal mutex and thus impose
acquire-release semantics not only on the user mutex *mtx
that is
involved in the calls to the wait functions, but on all calls to
cnd_signal
and cnd_broadcast
.
The feature had been inspired by a similar feature in POSIX, but it does not seem that the situation is better, there. Their text probably dates from before synchronization and happens-before had been formalized in C11, so it is as vague as the text in C23.
The only inter-thread time model that we have for multi-threaded executions is the happens-before relation, and that relation need synchronization either through atomic objects, fences or mutexes.
cnd_t
objects as a whole?Such a modification order would be consistent with the handling we
have for mtx_t
where C23 7.28.4.1 (7.30.4.1 in working draft N3550)
introduces such a (poorly worded) order.
cnd_t
which are the functions that participate in that modification order?One could assume that wait functions have two entries in the modification order, one for the entry into the call (maybe with release semantics) and the other for a wakeup (maybe with acquire semantics).
Signal and broadcast operations would probably only count each as one
operation. For these function not even some form of atomicity is
currently specified. Even the general paragraph 7.1.4 p5 that talks
about race conditions for library functions does not help: its
provision is explicitly only formulated for races that would result
from functions that access hidden state. Since these cnd_t
functions
potentially access the same data, nothing currently guarantees that
calls to these functions is atomic.
cnd_broadcast
and cnd_signal
load-modify-store operations on the cnd_t
?If yes, what would their memory ordering be? Two plausible candidates
would be memory_order_relaxed
and memory_order_acq_rel
.
cnd_t
synchronize with each other?I think it is unavoidable to add a "General" section to C23 7.28.3
(7.30.3 in working draft N3550) that describes a consistency model
between different calls that act on the same cnd_t
object. This
would best be done by claiming that there is a over-all modification
order on a cnd_t
variable on which wait, signal and broadcast
operate atomically.
How the synchronization constraints for these operations would be handled seems to be quite open and needs harmonization between POSIX, C++ and C at the least.