Day 5: Concurrency primitives: mutex, semaphore, deadlock
Keeping shared memory safe
Yesterday we said threads share memory, and that's exactly what makes concurrency dangerous: two threads reading and writing the same variable at the same time can interleave in ways that corrupt data (a race condition). Concurrency primitives exist to make sections of code safe from that interleaving.
Mutex
A mutex (mutual exclusion lock) allows only one thread at a time into a protected section of code. A thread must acquire the lock before entering, and release it after — any other thread trying to acquire it in the meantime simply waits. Simple, but a thread that forgets to release a mutex freezes everyone waiting on it forever.
Semaphore
A semaphore generalizes this to allow up to *N* threads into a section at once (a mutex is really just a semaphore with N=1). It's the right tool when you're protecting a limited pool of something — say, at most 10 concurrent database connections — rather than a single exclusive resource.
Deadlock
A deadlock happens when two (or more) threads each hold a lock the other needs, and neither will release theirs until it gets the other's — permanent stalemate. The four Coffman conditions are all required for deadlock to occur: mutual exclusion, hold-and-wait, no preemption, and circular wait. Prevention strategies typically attack one of these — most commonly, always acquiring locks in the same global order eliminates circular wait.
Back to the restaurant
Two chefs, one pan, one knife. Chef A grabs the pan and waits for the knife; Chef B grabs the knife and waits for the pan. Neither will put down what they're holding. That's a deadlock.
Payoff, later
Distributed 'deadlocks' — two services each waiting on a response from the other — are the same shape at a bigger scale, and Phase 7 (distributed systems) and Phase 21's circuit breakers exist largely to prevent them from cascading.
Key terms
- Race condition
- A bug where the outcome depends on the unpredictable timing/interleaving of concurrent operations.
- Mutex
- A lock allowing exactly one thread into a protected section at a time.
- Semaphore
- A generalized lock allowing up to N concurrent threads into a section.
- Deadlock
- A permanent stalemate where each of two or more threads holds a resource the other needs.
Which single change most directly prevents deadlock caused by circular wait?