Definition
Data Race
A data race occurs when two or more threads concurrently access the same memory location, at least one access is a write, and no synchronisation mechanism orders the accesses.
Formally, for threads and a shared variable , there is a data race iff
where means the two accesses are separated by a synchronisation edge (happens-before).
Relation to Race Condition
A data race is a condition on access patterns; a race condition is a condition on outcomes.
Data race race condition
A data race implies that the program’s observable behaviour depends on the interleaving of unsynchronised accesses, hence the outcome is nondeterministic — a race condition. The converse does not hold: a race condition can occur even with atomic variables if the logical ordering of updates is uncontrolled.
Race condition without data race
Two threads atomically increment a shared counter. No data race (the increment is atomic), but the final value depends on which thread executes first: the outcome is a race condition. The access pattern is safe; the program logic is not.
Hardware-Level Data Race
Instruction-level interleaving
Even a single high-level statement like
*lockvar = 1decomposes into multiple instructions (load, compare, store). If two threads execute these instruction sequences concurrently without atomicity, their individual instructions can interleave at the microarchitectural level, producing a data race on the lock variable itself.This is why a lock variable implemented with ordinary loads and stores fails under preemptive multithreading: the read of
*lockvarand the subsequent write are not indivisible.
Non-Atomic Access
Non-atomic word write
Assume a 16-bit word is written by copying two 8-bit halves separately. Let and thread write (two’s complement:
1111 1111 1111 1111).reads between the two half-writes:
should only ever observe or . The intermediate value is a data race artefact: the write was not atomic, so a concurrent read saw a torn state.