Skip to content
BytePatterns

Detecting Deadlock

Concurrency: lesson 12 of 15

Draw who waits for whom; a closed ring is the proof.

Lesson 12 of 15 · 5 min

Detecting Deadlock

Step 1 of 10

Four threads, all stuck. A stack trace tells you each one is waiting; it never tells you why nobody moves.

The Idea

A wait-for graph has one node per thread and an edge from a waiter to the holder it is blocked on. Following the edges from any thread either runs out — the chain ends at somebody who is running — or comes back around. That ring is the deadlock, and breaking it means aborting one member.

Real-World Example

Four people in a corridor, each waiting for the person ahead to step aside. Three of them form a circle and nobody moves. The fourth is only stuck because they queued behind the circle.

The Code

waits = {"t1": "t2", "t2": "t3", "t3": "t1", "t4": "t2"}

def stuck(graph, start):
    seen, at = [], start
    while at in graph:                 # who is this one waiting on?
        if at in seen:
            return seen[seen.index(at):]   # a closed ring: nobody can move
        seen.append(at)
        at = graph[at]
    return []                          # chain ends at a thread still running

print(stuck(waits, "t1"))              # ['t1', 't2', 't3']
print(stuck(waits, "t4"))              # ['t2', 't3', 't1'] -- queued behind it
freed = {k: v for k, v in waits.items() if k != "t3"}
print(stuck(freed, "t1"))              # [] -- abort one victim, ring broken

Python

Your turn

What does this print?

def stuck(graph, start):
  seen, at = [], start
  while at in graph:
      if at in seen:
          return seen[seen.index(at):]
      seen.append(at)
      at = graph[at]
  return []

print(stuck({"a": "b", "b": "c", "c": "b"}, "a"))

Mini quiz

1 / 3

In a wait-for graph, an edge from T1 to T2 means:

New lessons land every few weeks

Leave an address and we will tell you when the next one is up. That is the only reason we will use it.

One address, stored so we can email you. Nothing else, ever.