Wait for accounting work
The accounting thread holds L->mtx while it tests shared state: mtx_lock(&L->mtx); while (!L->finished && L->accounted == L->iteration) life_wait(&L->acco, &L->mtx); L->acco is a condition variable of type cnd_t. It identifies what the thread is waiting for; the expression in the while loop determines whether waiting is still necessary. The thread can leave the loop when an iteration needs accounting or the application has finished. section 20.5
A condition variable models a processing dependency between threads. In the same application, separate variables coordinate accounting, updating, and drawing. A thread waits when its shared-state test says there is no work; another thread signals a condition variable after advancing the work. section 20.5 section 20.8
TAKEAWAY: A notification is not the condition expression.
- Keep the wait inside a loop that tests shared state. A wait can return without the expression changing, even when the untimed interface is used. section 20.5
- Include termination in the test when shutdown must let a waiting thread proceed; the accounting loop tests L->finished as well as the iteration counts. section 20.5
- For a timed wait, supply the condition variable, mutex, and absolute time limit. The example computes a limit one second ahead, so a return may simply mean the wait timed out. section 20.5
The mutex protects the shared-state test and surrounding critical section. Entering cnd_wait or cnd_timedwait acts as a mutex release; returning from either acts as a mutex acquisition. Critical sections protected by that mutex therefore see the effects of earlier critical sections. Prefer cnd_timedwait over cnd_wait when reasoning about deadlock: a timed wait need not remain blocked indefinitely, though checking a program’s overall liveness still requires care. section 21.2 section 20.7
Listing 20.2 The account thread function of B9
int account_thread(void* Lv) {
life*restrict L = Lv;
while (!L->finished) {
// Blocks until there is work
mtx_lock(&L->mtx);
while (!L->finished && (L->accounted == L->iteration))
life_wait(&L->acco, &L->mtx);
// VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
life_account(L);
if ((L->last + repetition) < L->accounted) {
L->finished = true;
}
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
cnd_signal(&L->upda);
mtx_unlock(&L->mtx);
}
return 0;
}
The accounting-thread listing shows the mutex lock, repeated predicate test, wait, signal to the update thread, and mutex unlock in one control flow. section 20.5






