Race condition
Correctness that depends on the uncontrolled interleaving of concurrent operations. The principle under lost updates, double-submits, and TOCTOU.
Instances
- lost update
- double-submit
- TOCTOU
- forked log/chain
The principle
A race condition is when the result depends on timing you don't control — the order concurrent operations interleave. The defining trait: it passes in dev, passes in tests, and fails in production under load. The canonical shape is read-modify-write:
A reads n = 5
B reads n = 5
A writes 6
B writes 6 # should be 7 — one update lostTwo actors read the same value before either writes.
How it maps to practice
- Lost update — the counter example above; two writers clobber each other.
- Duplicate IDs across instances — each instance reads the same "next" value before any writes back. (Fixed by serializing the read-modify-write with
SELECT FOR UPDATE— a row-level distributed-lock.) - Forked log/chain — concurrent inserts read the same predecessor and both chain off it. (Hit this in an audit hash chain; fixed with an advisory lock.)
- Double-submit — user double-clicks; two requests both pass the "already submitted?" check.
- TOCTOU — time-of-check to time-of-use: you check a file/permission, then act, and it changed in between.
How to actually fix it
Make the critical section atomic, cheapest first:
- DB constraint — a
UNIQUEindex makes the duplicate impossible regardless of timing. - Atomic op —
UPDATE ... SET n = n + 1, not read-then-write. - A lock — only when 1 and 2 don't fit; it's a throughput cost.
An idempotent design sidesteps some races: if a repeat is harmless, a lost-then-retried op isn't corruption.
Say it clearly
"It works until two things happen at the same time." Not a buzzword target — the failure mode of skipping the analysis is "it passed all the tests," which is exactly why it ships.
In Korean
"경쟁 상태" (race = 경쟁/competition, literal) or "경합 상태" (경합/contention, arguably more precise for lock contention). Spoken Korean often just uses the English: "레이스 컨디션".