← Concepts

阅读中文版本

Deadlock Avoidance

Deadlock avoidance structures lock acquisition so the circular-wait condition cannot arise — by a global lock ordering, by lock timeouts, or by acquiring all locks atomically up front.

concurrency

Definition

Deadlock avoidance is the set of techniques — strict lock ordering (always acquire A before B), try-lock with timeout and rollback, or two-phase locking where all locks are acquired before any work — that prevent the four conditions of deadlock from holding simultaneously, with lock ordering the most common and provable.

Context and scope

Applied in database transactions, multi-resource service code, and any system where multiple locks must be held and the circular-wait risk is real.

Common misconceptions

  • Lock ordering is just a convention that cannot be enforced — it can be enforced by the lock API (ranked locks) or by static analysis; unenforced conventions rot
  • Timeouts solve deadlocks — they break the deadlock by aborting one transaction; they do not prevent it, and the retry can deadlock again

Anti-patterns

  • Acquiring locks in different orders in different code paths, so the ordering convention is violated and the deadlock the convention prevented occurs
  • Using try-lock with timeout and retrying the same acquisition order, so the deadlock recurs on every retry

Related concepts

Authoritative source

https://en.wikipedia.org/wiki/Deadlock_prevention_algorithms

What it is

Deadlock avoidance is the set of techniques — strict lock ordering (always acquire A before B), try-lock with timeout and rollback, or two-phase locking where all locks are acquired before any work — that prevent the four conditions of deadlock from holding simultaneously, with lock ordering the most common and provable. Applied in database transactions, multi-resource service code, and any system where multiple locks must be held and the circular-wait risk is real. The central difficulty is that interleaving is nondeterministic: the set of possible executions grows super-exponentially with the number of operations, and testing samples a vanishing fraction.

How it works

Correctness is established by reasoning about happens-before relationships, not by running more tests. Synchronization primitives are chosen for the specific guarantee needed — mutual exclusion, publication, or ordering — and composed only with a documented proof of absence of deadlock. Bounded resources apply backpressure rather than unbounded queuing that hides overload until memory exhausts.

When to apply and pitfalls

Apply whenever multiple flows share mutable state or resources. The dominant pitfall is reasoning sequentially about concurrent code — “this can’t happen because A finishes before B” — when in fact the scheduler can interleave at any instruction boundary. The second is using a coarse lock for simplicity and turning parallelism back into serialization.