liveBook · Manning

Cnd_timedwait

As explained in Modern C, Third Edition

cnd_timedwait is a C threads-library function that atomically releases a mutex while waiting for a condition variable and returns when signaled or when an absolute time limit is reached.

`cnd_timedwait` waits on a `cnd_t` condition variable with a mutex and an absolute time limit. The calling thread holds the mutex when it enters the wait; the call releases it while waiting and reacquires it before returning. A signal or the time limit can end the wait, but neither proves that the condition the thread needs is true. section 20.5 section 21.2

A one-second limit

`life_wait` obtains the current `TIME_UTC` time with `timespec_get`, adds one to `tv_sec`, and passes the resulting `struct timespec` to `cnd_timedwait`. The argument is an absolute limit, not a duration passed directly to the wait function. section 20.5

 int life_wait(cnd_t* cnd, mtx_t* mtx) {
   struct timespec now;
   timespec_get(&now, TIME_UTC);
   now.tv_sec += 1;
   return cnd_timedwait(cnd, mtx, &now);
 }

The wrapper shows all three wait arguments: the condition variable, the mutex, and the address of the absolute time limit. section 20.5

Keep the wait inside a loop that tests the actual condition. A condition variable identifies what a thread is waiting for; it is not the condition expression itself. In the accounting thread, the loop waits while the game is unfinished and the accounted iteration has caught up with the current iteration. On every return—including a timeout—the thread checks again before proceeding. An untimed wait also requires this check because it may return without a change to the expression. section 20.5

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 locks the mutex, tests its predicate in a loop, then performs its work and signals the update thread while still in the protected region. section 20.5

TAKEAWAY: Prefer `cnd_timedwait` over `cnd_wait` where an unlimited wait could threaten liveness. A deadline bounds an individual wait; progress still needs an argument about the surrounding predicates and threads. In the accounting and update threads, the relation between their iteration counts supplies that argument: when both repeatedly wait, a return eventually lets one of them advance its count. section 20.7

Entering `cnd_timedwait` is a mutex release operation, and returning from it is a mutex acquire operation. Critical sections protected by that same mutex therefore occur sequentially, with effects from earlier protected sections visible to the returning thread. section 21.2

How Modern C, Third Edition covers it

How deep it goes
Explains deadline construction, predicate rechecks, liveness reasoning, and the wait’s mutex release-and-acquire behavior.
Examples
Uses a one-second `life_wait` wrapper and accounting, update, and drawing wait loops.
What it assumes
Assumes C thread and mutex usage while distinguishing a condition variable from the expression being tested.
What you can do after
Apply it via the C threads library to time-limit waits, recheck predicates, and reason about progress.
How it connects
Connects condition variables to mutexes, critical sections, condition predicates, deadlock, and liveness.

Also explained in

Compare how 2 books explain cnd_timedwait →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Modern C, Third Edition. The section links point to the parts of the book it draws on.