Part 0 · 2 chapters · ~12 min

Races

Concurrency versus parallelism, IO-bound and CPU-bound work, data races and race conditions (not the same thing), races in single-threaded async code, check-then-act and read-modify-write bugs, and race detectors (Go -race, ThreadSanitizer).

1

Concurrency and parallelism

Rob Pike's line is the cleanest summary: concurrency is about dealing with lots of things at once; parallelism is about doing lots of things at once. A well-structured concurrent program can be run in parallel; a parallel program without good concurrent structure is a source of bugs.

CONCURRENCY VS PARALLELISM
structure versus simultaneous execution
one core, two tasksinterleaved: concurrent, not paralleltwo cores, two taskssimultaneous: parallelIO-bound workwaiting dominates: concurrency helpsCPU-bound workcomputing dominates: parallelism helps
swipe the figure sideways, or tap expand for full screen
1/5
concurrency
Concurrency is a way of structuring a program as independent tasks that can make progress in overlapping time. A single core can run concurrent tasks by interleaving them: Node does this with one thread.
structure: overlapping taskspossible on one core
2

Races without threads, and race detectors

code
// the fix: make the check and the update one atomic operation in the database
const r = await db.query(
  'UPDATE wallets SET balance_kobo = balance_kobo - $1 WHERE id = $2 AND balance_kobo >= $1 RETURNING balance_kobo',
  [amount, walletId]);
if (r.rowCount === 0) throw new InsufficientFunds();

A data race is two threads accessing the same memory concurrently with at least one write and no synchronisation: undefined behaviour in C, C++ and Rust (where safe Rust forbids it at compile time), a bug everywhere. A race condition is any outcome depending on timing, including the async example, which has no data race at all. Detectors: go test -race, ThreadSanitizer for C, C++ and Rust, and stress tests that run the same operation concurrently thousands of times.

A RACE IN SINGLE-THREADED JAVASCRIPT
no threads, still a lost update: the await is the interleaving point
request 1wallet balancerequest 2await getBalance() → 100await getBalance() → 100
swipe the figure sideways, or tap expand for full screen
1/3
two requests
Two withdrawal requests for ₦80 arrive at almost the same time. JavaScript runs one at a time, but each awaits the database read.
each awaits the readthe loop interleaves them