When multiple threads access shared data and at least one writes, the result can depend on timing — a race condition. The section of code that touches shared data is the critical section, and the OS provides synchronization tools (mutexes, semaphores) to ensure only one thread is inside it at a time.
Critical section & mutual exclusion
A race condition is when the outcome depends on the unpredictable order of thread execution. The fix is mutual exclusion: protect the critical section so only one thread enters at a time, using a lock (mutex) or a semaphore.
Mutex vs semaphore
| Tool | What it is |
|---|---|
| Mutex | a lock owned by one thread; only the owner unlocks it |
| Binary semaphore | a 0/1 signal; any thread can signal |
| Counting semaphore | allows up to N threads (N resources) |
Deadlock: the four Coffman conditions
- Mutual exclusion — a resource is held by one process at a time.
- Hold and wait — a process holds one resource while waiting for another.
- No preemption — resources can't be forcibly taken away.
- Circular wait — a cycle of processes each waiting on the next.
⚡ The edge
- All four Coffman conditions must hold for a deadlock — break any one to prevent it (e.g. a global lock ordering kills circular wait).
- Mutex = ownership (lock/unlock by the same thread); semaphore = a counter/signal any thread can change. Use a mutex for mutual exclusion, a counting semaphore to limit access to N resources.
Worked example
'What is a race condition and how do you prevent it?'
- Define it: two or more threads access shared data concurrently and the result depends on timing.
- Identify the critical section — the code touching the shared data.
- Prevent it with mutual exclusion: a mutex or semaphore so only one thread is in the critical section at a time.
Answer: A timing-dependent bug on shared data; prevented by protecting the critical section with a lock.
Worked example
'How can you prevent deadlock?'
- Recall the four conditions: mutual exclusion, hold-and-wait, no preemption, circular wait — all must hold.
- Breaking any one prevents deadlock.
- The most practical is breaking circular wait by acquiring locks in a fixed global order.
Answer: Deny one of the four Coffman conditions — e.g. a global lock ordering to break circular wait.
⚠ Watch out
- A deadlock needs all four conditions — prevention means breaking just one.
- Don't confuse deadlock (stuck forever) with starvation (keeps losing out) or a livelock (active but no progress).
- A mutex must be unlocked by the same thread that locked it; a semaphore has no such ownership.