A structured lesson workspace with readable content, hands-on examples, and a clean path to completion.
A race condition occurs when two or more threads access shared data concurrently and at least one access is a write. The result depends on the timing of the thread scheduler. Run the program ten times and you might get ten different answers. The bug is not in the logic. The logic is correct for sequential execution. The bug is in the assumption that operations are atomic when they are not. incrementing a counter is three machine instructions: read, add, write. Two threads can interleave those instructions and lose an update.
#include <stdio.h>#include <pthread.h>#define ITERATIONS 10000000int shared_counter = 0;void *increment(void *arg) {(void)arg;for (int i = 0; i < ITERATIONS; i++) {shared_counter++;}return NULL;}int main(void) {pthread_t t1, t2;pthread_create(&t1, NULL, increment, NULL);pthread_create(&t2, NULL, increment, NULL);pthread_join(t1, NULL);pthread_join(t2, NULL);printf("Expected: %d\n", 2 * ITERATIONS);printf("Actual: %d\n", shared_counter);printf("Lost: %d updates\n", 2 * ITERATIONS - shared_counter);return 0;}
Different result every run. Millions of updates lost. The shared_counter++ operation is not atomic. Thread 1 reads the counter. Thread 2 reads the same value. Both add 1. Both write back. One increment is lost. This happens millions of times per second. The fix is a mutex, which we cover in the next lesson. The diagnosis is the race: concurrent unsynchronized access to shared mutable state.
ThreadSanitizer (TSan) detects the data race and reports the exact line, the access size, and the two threads involved. It does this without requiring the race to manifest as a wrong result. It detects the potential, not just the actual. Run your threaded tests under TSan in CI. It catches races that might not appear in a hundred manual runs.
Race conditions are the defining bug of concurrent programming. They are nondeterministic, timing-dependent, and invisible in single-threaded testing. The tools exist: TSan for detection, mutexes for prevention. The discipline is required: every shared mutable variable must be protected or documented as thread-local. Next: mutexes, the lock that serializes access to shared state.
Finish the lesson once you have worked through the material. This awards ★ 40 XP.