Deadlock Detection & Recovery — Wait-For Graph & Detection Algorithm
Press Next → or use ← → arrow keys
The Story That Explains Detection & Recovery
That is detection + recovery: allow all four Coffman conditions, let deadlock occur if it will, detect it periodically, and then recover.
Because it imposes no restrictions up front, this approach gives the highest resource utilisation. You only pay when you actually run the detector — which is why databases and batch systems favour it.
Detection — Two Cases
Abstract the resources away: draw an edge Pᵢ → Pⱼ whenever Pᵢ is waiting for a resource that Pⱼ currently holds. The result is a graph of processes only — and a cycle in it means a deadlock.
A Cycle in the Wait-For Graph
Each edge says "the tail process is blocked waiting for a resource the head process holds." When these wait-for edges close a loop, every process in it is waiting on the next — and none can release. For single-instance resources, this cycle is proof of deadlock.
Multiple-Instance Detection Algorithm
# Detection — m resource types, n processes Work = Available Finish[i] = (Allocation[i] == 0) # idle procs are trivially done while ∃ i : Finish[i]==false and Request[i] <= Work: Work = Work + Allocation[i] # pretend Pi finishes & releases Finish[i] = true if ∃ i : Finish[i]==false: return "DEADLOCK" # those procs are deadlocked else: return "NO DEADLOCK"
It looks like the Banker's safety check, but it walks the Request matrix (what's needed
now), not Need (the declared maximum). A process with a zero request row is assumed
able to finish. Any process still Finish[i] == false at the end is deadlocked.
Detection Example — Is There a Deadlock?
5 processes (P0–P4), 3 resources A/B/C. Total A=7, B=2, C=6. Allocation sums to the totals, so Available = [0, 0, 0].
| A | B | C | |
|---|---|---|---|
| P0 | 0 | 1 | 0 |
| P1 | 2 | 0 | 0 |
| P2 | 3 | 0 | 3 |
| P3 | 2 | 1 | 1 |
| P4 | 0 | 0 | 2 |
| A | B | C | |
|---|---|---|---|
| P0 | 0 | 0 | 0 |
| P1 | 2 | 0 | 2 |
| P2 | 0 | 0 | 0 |
| P3 | 1 | 0 | 0 |
| P4 | 0 | 0 | 2 |
| A | B | C |
|---|---|---|
| 0 | 0 | 0 |
Two processes (P0, P2) have zero requests — they can finish immediately and hand back their resources, unblocking the rest.
Running the Detector — No Deadlock
| Pick | Request ≤ Work? | Work before | Work after (+Alloc) |
|---|---|---|---|
| P0 | [0,0,0] ≤ [0,0,0] ✓ | [0,0,0] | [0,1,0] |
| P2 | [0,0,0] ≤ [0,1,0] ✓ | [0,1,0] | [3,1,3] |
| P1 | [2,0,2] ≤ [3,1,3] ✓ | [3,1,3] | [5,1,3] |
| P3 | [1,0,0] ≤ [5,1,3] ✓ | [5,1,3] | [7,2,4] |
| P4 | [0,0,2] ≤ [7,2,4] ✓ | [7,2,4] | [7,2,6] — all finish |
One Tiny Change → Deadlock
Same system as before, but now P2 is also waiting — for one unit of C. P0 still finishes (Work → [0,1,0]), but then every remaining process needs resource C, and Work has zero C to give. Nobody can proceed. A one-unit change flipped the system from safe to deadlocked, trapping {P1, P2, P3, P4}.
When to Run the Detector
PostgreSQL and Oracle check on a lock-wait timeout and abort the cheapest
transaction (errors 40P01 / ORA-00060); MySQL InnoDB keeps an internal
wait-for graph and checks on every lock wait. The rule for developers: catch the deadlock error and
retry.
Recovery — Two Approaches
Pick the lowest-cost victim, weighing priority, CPU time already spent, time remaining, resources held, and interactive-vs-batch. Crucially, fold in how many times a process has already been a victim — otherwise the same unlucky process is picked forever and starves.
Iterative Victim Selection — Kill the Cheapest
The cycle P1→P2→P3→P4→P1 has costs 200 / 50 / 150 / 80. Aborting P2 (cost 50) frees its resources, and re-running detection shows the cycle is gone — so total work lost is just 50. If one victim weren't enough, you'd kill the next-cheapest and re-check, tracking the running cost.
Preemption & Rollback
To preempt a resource safely, roll the victim back to the last checkpoint where it didn't hold that resource — here CP-2. Everything it did between CP-2 and the preemption is lost work and must be redone. That's the price of preemption, and why it needs a checkpointing system underneath.
Prevention vs Avoidance vs Detection
| Aspect | Prevention | Avoidance | Detection + Recovery |
|---|---|---|---|
| When applied | Design time | Each request | Periodic / event-driven |
| Coffman conditions | Breaks ≥1 | Allows all 4 | Allows all 4 |
| A-priori info | None | Max declarations | None |
| Overhead | Zero | O(m·n²) / request | O(m·n²) / invocation |
| Resource use | Often low | Moderate | High |
| Best fit | General OS, kernel | Real-time, embedded | Databases, batch systems |
Because it maximises resource use and only acts when trouble actually strikes, detection + recovery is the default for systems running huge numbers of concurrent transactions — PostgreSQL, Oracle, MySQL — where the occasional aborted-and-retried transaction is a fine price to pay.
Eight Rules for Detection & Recovery
Catch It, Then Clean It Up
From building a wait-for graph and spotting its cycle, to running the multi-instance detection algorithm on the Request matrices, to selecting a minimum-cost victim and rolling it back — you can handle the full detect-and-recover workflow, by hand or in code.
You've now completed the entire deadlock arc — model, conditions, prevention, avoidance, detection and recovery. The next major unit is memory management: contiguous allocation, paging and segmentation, then virtual memory.
🔍 End of tutorial · Press ← to review, or click Restart