Module 2 · Unit 7 of 5
Deadlocks
The failure mode of synchronization. A set of processes is deadlocked when each is waiting for a resource held by another, and none can proceed. This unit develops the four necessary conditions, the resource-allocation graph formalism, and the four families of approaches — prevention, avoidance, detection, and recovery.
Module 2 · Unit 7
Deadlocks
What happens when synchronization goes wrong in the worst possible way: no progress at all, for every party involved. This unit gives you the tools to reason about deadlock, prevent it where you can, and detect and recover from it where you cannot.
01 Unit learning outcomes
Upon completion of this unit you will be able to
- U7.1 — Explain deadlock conditions.
- U7.2 — Analyse deadlock occurrence.
- U7.3 — Apply prevention and avoidance techniques.
- U7.4 — Use detection techniques.
- U7.5 — Evaluate recovery approaches.
This unit addresses course learning outcomes CLO3 and CLO8. It closes Module 2.
02 Lessons in this unit
The first three lessons develop the theory. The final four examine the four families of practical approaches, from the most conservative (prevention) to the most pragmatic (detection and recovery).
Deadlock Fundamentals
What deadlock is, how it differs from starvation and livelock, and why it is hard to detect.
Lesson 7.2Deadlock Conditions
Coffman's four necessary conditions — and why all four must hold simultaneously.
Lesson 7.3Resource Allocation Graphs
Modelling resource state formally, cycles, and the difference between single and multiple instances.
Lesson 7.4Prevention
Breaking one of the four conditions — the design-time approach that avoids deadlock entirely.
Lesson 7.5Avoidance
Using advance information about future requests to keep the system in a safe state.
Lesson 7.6Banker's Algorithm
The classical avoidance algorithm — the safety check, the resource-request algorithm, and its limits.
Lesson 7.7Detection and Recovery
Allowing deadlock to occur, detecting it, and recovering through preemption, rollback, or termination.
03 What you will learn, lesson by lesson
7.1 Deadlock Fundamentals
- Define deadlock.
- Distinguish deadlock from starvation.
- Distinguish deadlock from livelock.
- Analyse system-level effects.
- Recognise deadlock scenarios.
7.2 Deadlock Conditions
- State mutual exclusion.
- State hold-and-wait.
- State no-preemption.
- State circular wait.
- Analyse condition necessity.
7.3 Resource Allocation Graphs
- Construct resource allocation graphs.
- Identify cycles.
- Interpret graph structure.
- Analyse multiple instances.
- Apply cycle detection.
7.4 Prevention
- Break mutual exclusion.
- Break hold-and-wait.
- Break no-preemption.
- Break circular wait.
- Evaluate prevention costs.
7.5 Avoidance
- Define safe state.
- Explain resource reservation.
- Analyse safe sequences.
- Evaluate avoidance assumptions.
- Compare avoidance and prevention.
7.6 Banker's Algorithm
- Describe the safety algorithm.
- Execute the resource-request check.
- Trace algorithm state.
- Analyse complexity.
- Evaluate practical use.
7.7 Detection and Recovery
- Apply detection algorithms.
- Explain termination recovery.
- Explain preemption recovery.
- Explain rollback recovery.
- Evaluate recovery trade-offs.
04 Worked example
A deadlock that appears in real code, and the classic fix.
Two accounts, two locks, one deadlock
A banking system has two accounts, each with its own mutex. Two threads attempt transfers in opposite directions.
void transfer(Account *from, Account *to, int amount) {
pthread_mutex_lock(&from->lock);
pthread_mutex_lock(&to->lock);
from->balance -= amount;
to->balance += amount;
pthread_mutex_unlock(&to->lock);
pthread_mutex_unlock(&from->lock);
}
/* Thread A */
transfer(&account1, &account2, 100);
/* Thread B (runs concurrently) */
transfer(&account2, &account1, 50);
-
The interleaving. Thread A acquires
account1->lock, then is preempted. Thread B acquiresaccount2->lock. Thread A now waits foraccount2->lockwhile holdingaccount1->lock. Thread B waits foraccount1->lockwhile holdingaccount2->lock. Circular wait. Deadlock. - Check the four conditions. Mutual exclusion — yes, both locks are exclusive. Hold-and-wait — yes, each thread holds one lock while requesting another. No-preemption — yes, neither thread releases voluntarily. Circular wait — yes.
- Fix by breaking circular wait. Impose a global ordering on locks. Lock the lower-numbered account first, regardless of which is "from" and which is "to".
void transfer(Account *a, Account *b, int amount) {
Account *first = (a->id < b->id) ? a : b;
Account *second = (a->id < b->id) ? b : a;
pthread_mutex_lock(&first->lock);
pthread_mutex_lock(&second->lock);
/* ... */
}
With a consistent global ordering, circular wait is impossible.
Thread B now also locks account1 first, so the two
threads contend on the same lock rather than forming a cycle.
One proceeds, the other waits its turn.
The general rule
If your program must hold more than one lock at a time, define a global ordering and always acquire locks in that order. This one discipline eliminates circular wait — and with it, the majority of deadlocks in real systems.
05 Required reading
- OSTEP — Chapter 32, Concurrency Bugs, and the discussion of deadlock in Chapter 31.
- Operating System Concepts — Chapter 8, Deadlocks, in full.
- Dijkstra, E. W. Cooperating Sequential Processes (1965) — the original description of the deadlock problem and the Banker's algorithm.
06 Unit discussion
Discussion prompt
General-purpose operating systems do not use the Banker's algorithm, even though it is provably correct and avoids deadlock entirely. Real systems use prevention (lock ordering) where possible, and detection-and-recovery elsewhere.
Why? Consider the assumptions the Banker's algorithm makes about advance knowledge of resource needs, the complexity of running the safety check on every request, and the actual behaviour of workloads in the field. Argue for or against the use of avoidance in a modern server operating system.
Post your response to the Unit 7 discussion forum and reply to at least two classmates. Supports CLO3 and CLO7.
07 Laboratory connection
Lab 6 — Deadlock Analysis is completed at the
end of this unit. It asks you to construct a deadlock
deliberately, observe it under gdb, diagnose it
using the four conditions, and repair it.
| Lesson | Lab 6 exercise |
|---|---|
| 7.1–7.2 Deadlock | Construct a two-thread deadlock and confirm the four conditions |
| 7.3 Graph | Draw the resource allocation graph for the lab program |
| 7.4 Prevention | Fix the program with lock ordering; verify with a stress test |
| 7.6 Banker's | Implement the safety check; feed it a synthetic state table |
| 7.7 Detection | Attach gdb, dump all thread stacks, identify the cycle |
08 Knowledge check & quiz
Quick check before you begin
Question 1
State Coffman's four necessary conditions for deadlock. Why must all four hold simultaneously?
Show answer
Question 2
A resource allocation graph contains a cycle. Does that guarantee deadlock? Explain.
Show answer
Question 3
Why does imposing a global lock ordering break circular wait?