A race condition occurs when the program's behavior depends on the relative timing of events, such as the order in which threads execute.


The Problem

Thread A:           Thread B:
read x (= 0)        read x (= 0)
x = x + 1           x = x + 1
write x (= 1)       write x (= 1)

Expected: x = 2
Actual:   x = 1  ← Lost update!

Both threads read the same initial value, compute independently, and overwrite each other.


Types of Race Conditions

Type Description
Read-Modify-Write Check-then-act on shared state
Check-Then-Act Condition changes between check and action
Compound Operations Multiple operations that should be atomic

Detection


Prevention Strategies

Strategy How
Mutex/Lock Ensure exclusive access
Atomic operations Hardware-level indivisibility
Immutability No shared mutable state
Message passing Actors/channels — no shared memory
Thread-local storage Each thread owns its data

In Practice

Bad:

var counter int

func increment() {
    counter++  // Race condition!
}