Accounting for a changing board
An accounting thread must scan a shared position matrix while other threads may update it. It locks L->mtx, waits until an iteration needs accounting, calls life_account(L), signals the update thread, and unlocks the mutex. The scan is part of a critical section: it cannot safely overlap a conflicting access to the same protected data. section 18.5
A critical section is a code path that operates on shared data not protected by atomic operations. A mutex of type mtx_t protects it. mtx_lock waits until no other thread is inside a section protected by that same mutex; mtx_unlock releases the lock. TAKEAWAY: Threads that access the protected data must coordinate through the same mutex. section 18.4 section 18.7
The boundary depends on the work. The input thread needs a lock when a command changes a cluster of board cells, but its other cases interact only with atomic objects. Accounting, updating, and drawing each place most of a loop body inside a critical section. Arrays cannot be declared _Atomic here, making a mutex the practical protection for the larger board data. section 18.4 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 mtx_lock through its wait loop and matrix scan to cnd_signal and mtx_unlock; the marked computation lies within the protected region. section 18.5
Waiting for work is different from protecting the work. A condition variable identifies what a thread waits for; a condition expression determines whether it can proceed. The accounting thread tests that expression in a while loop because a wait may return without making the condition true. Its timed wait uses both a condition variable and the mutex; a waiting thread reacquires the mutex before continuing. section 18.5
Mutex operations also provide linearizability: after acquiring a mutex, a thread can rely on operations completed before other threads released that same mutex having taken effect. mtx_trylock offers a test that can avoid waiting; mtx_timedlock limits how long the caller waits. section 18.4








