Part 3 · 2 chapters · ~12 min

Synchronisation

Race conditions and critical sections, atomic instructions, spinlocks and mutexes, semaphores, condition variables and monitors, readers-writer locks, deadlock and its four conditions, prevention by lock ordering, livelock and starvation, and the same problems in databases and distributed systems.

7

Races and critical sections

code
// a condition variable: a bounded queue where consumers sleep until items arrive (pseudocode, pthread-style)
lock(m);
while (queue.empty()) wait(not_empty, m);   // releases m while sleeping; re-acquires on wake; loop for spurious wakeups
item = queue.pop();
signal(not_full);
unlock(m);
A RACE CONDITION, STEP BY STEP
two threads increment a shared balance; one update is lost
thread 1memory: balancethread 2read 100read 100
swipe the figure sideways, or tap expand for full screen
1/4
the read
Both threads read the same balance before either writes. Each believes it is working from the current value.
both read 100nothing is wrong yet
8

Deadlock

Coffman conditionbreak it by
mutual exclusionlock-free structures, or sharing less
hold and waitacquire all locks at once, or none
no preemptiontimeouts (tryLock, lock_timeout) and retry
circular waita global lock order: always lock accounts in id order (Ledgers part 1 does this)

All four must hold for deadlock; removing any one prevents it. Databases detect deadlocks with a wait-for graph and abort a victim (MySQL course part 5); distributed locks need leases and fencing tokens (Distributed Systems part 6). Livelock (everyone retrying in lockstep) is fixed with randomised backoff; starvation with fair queues.