Skip to content

Data race

Category: Hazards · Status: stub · Lessons: chapter 02, Shared state

One line: Two threads access the same memory at the same time, at least one of them writing, with nothing synchronizing them — undefined behaviour in C and C++, a compile error in safe Rust.

Also called: unsynchronized access.

How it connects

flowchart LR
  n_atomic_variable["Atomic variable"]
  n_data_race["Data race"]
  n_data_race_freedom["Data-race freedom by construction"]
  n_immutability["Immutability"]
  n_mutual_exclusion["Mutual exclusion"]
  n_race_condition["Race condition"]
  n_safety_failure["Safety failure"]
  n_send_and_sync["Send and Sync"]
  n_shared_memory["Shared memory"]
  n_thread_confinement["Thread confinement"]
  n_thread_local_storage["Thread-local storage"]
  n_atomic_variable -->|prevents| n_data_race
  n_data_race ---|vs| n_race_condition
  n_data_race -->|is a| n_safety_failure
  n_data_race_freedom -->|prevents| n_data_race
  n_immutability -->|prevents| n_data_race
  n_mutual_exclusion -->|prevents| n_data_race
  n_send_and_sync -->|prevents| n_data_race
  n_shared_memory -->|can cause| n_data_race
  n_thread_confinement -->|prevents| n_data_race
  n_thread_local_storage -->|prevents| n_data_race
  classDef center stroke-width:3px
  class n_data_race center
  classDef outside stroke-dasharray: 4 3
  class n_atomic_variable,n_data_race_freedom,n_immutability,n_mutual_exclusion,n_race_condition,n_safety_failure,n_send_and_sync,n_shared_memory,n_thread_confinement,n_thread_local_storage outside

In each language

Rust The Rustonomicon ↗: safe Rust guarantees there are none; in unsafe code a data race is undefined behaviour ↗
Go Compiles and runs: the memory model ↗ requires such access to be serialized and warns that races can corrupt memory; the race detector ↗ (-race) reports them at run time
C Memory model and data races ↗: if a data race occurs, the behaviour of the program is undefined
C++ Multi-threaded executions and data races ↗: a data race is undefined behaviour; std::atomic or a mutex avoids it
Java Not undefined behaviour, but JLS §17.4 ↗ specifies a memory model with few guarantees for unsynchronized reads, and §17.7 ↗ warns that writes to long and double are not atomic
Python In the free-threaded build ↗ built-in types like dict, list and set use internal locks, much as the GIL protected them; the program's own invariants still need threading.Lock
JavaScript Only memory shared through a SharedArrayBuffer can race; Atomics operations make its reads and writes predictable
Swift The Swift Programming Language: Concurrency ↗: most data races are compile-time errors, and those found only at run time terminate the program

Where to read more