liveBook · Manning

Locking

As explained in Modern C

Mutual exclusion is a synchronization property ensuring that at most one thread accesses a protected region at a time.

One thread at the shared state

An accounting thread calls `mtx_lock(&L->mtx)` before checking whether a new iteration needs accounting. When work is ready, it calls `life_account(L)`, signals the update thread, and calls `mtx_unlock(&L->mtx)`. The update and draw threads use the same mutex around their own work on the shared state. section 18.5

Listing 18.2. The account thread function of B9
 99   int account_thread(void* Lv) {
100     life*restrict L = Lv;
101     while (!L->finished) {
102       // Blocks until there is work
103       mtx_lock(&L->mtx);
104       while (!L->finished && (L->accounted == L->iteration))
105         life_wait(&L->acco, &L->mtx);
106
107       // VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
108       life_account(L);
109       if ((L->last + repetition) < L->accounted) {
110         L->finished = true;
111       }
112       // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
113
114       cnd_signal(&L->upda);
115       mtx_unlock(&L->mtx);
116     }
117     return 0;
118   }


!@%STYLE%@!
{"css":"{\"css\": \"font-weight: bold;\"}","target":"[[{\"line\":0,\"ch\":1},{\"line\":0,\"ch\":3}],[{\"line\":0,\"ch\":6},{\"line\":0,\"ch\":9}],[{\"line\":0,\"ch\":25},{\"line\":0,\"ch\":29}],[{\"line\":1,\"ch\":0},{\"line\":1,\"ch\":3}],[{\"line\":1,\"ch\":13},{\"line\":1,\"ch\":21}],[{\"line\":2,\"ch\":0},{\"line\":2,\"ch\":3}],[{\"line\":2,\"ch\":8},{\"line\":2,\"ch\":13}],[{\"line\":5,\"ch\":10},{\"line\":5,\"ch\":15}],[{\"line\":3,\"ch\":0},{\"line\":3,\"ch\":3}],[{\"line\":4,\"ch\":0},{\"line\":4,\"ch\":3}],[{\"line\":4,\"ch\":10},{\"line\":4,\"ch\":18}],[{\"line\":5,\"ch\":0},{\"line\":5,\"ch\":3}],[{\"line\":2,\"ch\":8},{\"line\":2,\"ch\":13}],[{\"line\":5,\"ch\":10},{\"line\":5,\"ch\":15}],[{\"line\":6,\"ch\":0},{\"line\":6,\"ch\":3}],[{\"line\":7,\"ch\":0},{\"line\":7,\"ch\":3}],[{\"line\":8,\"ch\":0},{\"line\":8,\"ch\":3}],[{\"line\":9,\"ch\":0},{\"line\":9,\"ch\":3}],[{\"line\":10,\"ch\":0},{\"line\":10,\"ch\":3}],[{\"line\":1,\"ch\":9},{\"line\":1,\"ch\":11}],[{\"line\":6,\"ch\":13},{\"line\":6,\"ch\":15}],[{\"line\":9,\"ch\":11},{\"line\":9,\"ch\":13}],[{\"line\":10,\"ch\":10},{\"line\":10,\"ch\":12}],[{\"line\":11,\"ch\":0},{\"line\":11,\"ch\":3}],[{\"line\":11,\"ch\":26},{\"line\":11,\"ch\":30}],[{\"line\":12,\"ch\":0},{\"line\":12,\"ch\":3}],[{\"line\":13,\"ch\":0},{\"line\":13,\"ch\":3}],[{\"line\":14,\"ch\":0},{\"line\":14,\"ch\":3}],[{\"line\":15,\"ch\":0},{\"line\":15,\"ch\":3}],[{\"line\":15,\"ch\":10},{\"line\":15,\"ch\":20}],[{\"line\":16,\"ch\":0},{\"line\":16,\"ch\":3}],[{\"line\":16,\"ch\":10},{\"line\":16,\"ch\":20}],[{\"line\":17,\"ch\":0},{\"line\":17,\"ch\":3}],[{\"line\":18,\"ch\":0},{\"line\":18,\"ch\":3}],[{\"line\":18,\"ch\":8},{\"line\":18,\"ch\":14}],[{\"line\":19,\"ch\":0},{\"line\":19,\"ch\":3}]]"}
!@%STYLE%@!

Follow the accounting thread from lock acquisition through its wait loop, computation, signal, and unlock. section 18.5

A mutex provides mutual exclusion for a critical section: code that accesses critical shared data. In C, `mtx_t` is a mutex type from `<threads.h>`. Calling `mtx_lock` blocks until no other thread is inside a critical section protected by that same mutex; `mtx_unlock` releases it. The protection depends on the threads using the same mutex. section 18.4

A game board is an example of data that needs this protection: arrays cannot be specified with `_Atomic`, and an atomic workaround would not be efficient. Smaller shared values can instead be `_Atomic`. TAKEAWAY: Mutex operations also provide linearizability. After acquiring a mutex, a thread can rely on operations performed before another thread released that mutex having taken effect. section 18.4 section 18.7

Related interfaces and rules:

  • `mtx_trylock` tests whether the lock can be acquired without waiting; `mtx_timedlock` limits the wait. `mtx_init` and `mtx_destroy` are the initialization and destruction interfaces. section 18.4
  • A condition-variable wait takes a mutex and may return even when the condition expression has not changed. Keep the wait inside a loop that checks the expression again. section 18.5
  • A thread blocked on a mutex or condition variable frees processing resources for other threads. section 18.6

How Modern C covers it

How deep it goes
Defines mutexes and critical sections, explains acquisition and linearizability, and shows guarded thread code without detailing mutex implementation.
Examples
Uses a shared game board and accounting, update, and draw thread functions with lock, wait, signal, and unlock calls.
What it assumes
Assumes C thread functions and shared data are readable; defines mutex and critical-section terminology in context.
What you can do after
Apply it via C `<threads.h>` mutex operations to guard critical sections and coordinate shared-state work with condition variables.
How it connects
Connects locking to atomic objects, critical sections, condition variables, linearizability, and thread scheduling.

Also explained in

Compare how 18 books explain locking →

Related concepts

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