Skip to content
BytePatterns

Deadlock

Concurrency: lesson 4 of 15

Everyone holding what the next one needs.

Lesson 4 of 15 · 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:

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.