Skip to content
BytePatterns

Deadlock

Concurrency: lesson 4 of 10

Everyone holding what the next one needs.

Lesson 4 of 10 · 5 min

Deadlock

Step 1 of 10

Two threads, two locks, and each thread needs both before it can finish its transfer.

The Idea

Deadlock is a standoff. Thread one holds lock A and wants B; thread two holds B and wants A. Neither will let go of what it has, so both wait forever. No exception is raised — the work simply stops.

Real-World Example

Two joinery apprentices glueing a frame. One has the clamp and needs the glue; the other has the glue and needs the clamp. Both stand there holding their half, each perfectly reasonably waiting for the other to finish first.

The Tradeoff

Fine-grained locks buy real parallelism and hand you the possibility of a cycle. Imposing one global acquisition order removes the cycle and costs nothing at runtime. Timeouts are the fallback: they convert a permanent hang into a retry, which is a friendlier bug but still a bug.

import threading

locks = {"alice": threading.Lock(), "bob": threading.Lock()}

def transfer(src, dst):
    first, second = sorted([src, dst])     # always the same order
    with locks[first], locks[second]:
        print("moved", src, "->", dst)

transfer("bob", "alice")
transfer("alice", "bob")                   # no cycle: alice's lock goes first

Your turn

Put the steps in the right order.

  1. Thread 1 requests lock B, which Thread 2 holds, and blocks
  2. Thread 1 acquires lock A
  3. Both threads wait forever, each holding what the other needs
  4. Thread 2 acquires lock B

Mini quiz

1 / 3

A deadlock needs a cycle of threads that are: