Skip to main content

Data Races and Happens-Before

advanced11 min readLesson 159 of 204

Two threads, one non-atomic variable, at least one write: that is a race, and every outcome is the standard's blessing.

The definition that matters

A data race exists when two threads access the same memory location, at least one access is a write, and the accesses are not ordered by synchronization. Racing accesses are undefined behavior โ€” not "one of the two wins", but anything: torn reads, phantom values, miscompiled loops. (Two concurrent reads are fine.)

Synchronization = happens-before

The model orders operations with happens-before. You get it from:

  • program order within a thread,
  • thread creation (t.join(), everything the thread did happens-before join returns),
  • mutexes (everything before unlock() happens-before everything after the next lock()),
  • suitably ordered atomic operations (next lesson).

If two accesses can't be ordered by any happens-before chain and one is a write โ€” race. If they are ordered โ€” well-defined, and you can say which value the reader sees.

The default instinct

No synchronization primitive between two threads touching shared data? Race. "It works on my machine" only means the race hasn't bitten yet โ€” races are timing-dependent and the graded exercises make them deterministic by construction.

Now practice

Atomics in MotionRace-free counting across threads and the canonical acquire/release publish of a payload.2 challenges ยท ยท ~22 min