Start here
Thread safety (three pillars)
Atomicity: critical sections appear indivisible w.r.t. other threads. Visibility: writes become observable to other cores in defined ways (barriers, locks, atomics). Ordering: compiler and CPU reorderings must not break your protocol.
By the end of this page you should be able to
- Contrast a data race with a higher-level race condition.
- Explain check-then-act and why it needs a mutex or CAS.
- State what “happens-before” gives you informally.
Hardware reality
Operating systems · Threads
Thread safety
Invariants under concurrency
TL;DR
Thread safety means your API maintains correct invariants when called concurrently, usually via mutexes, atomics, or confinement to a single thread. “Thread-safe” is not transitive: composing two thread-safe components can still race if their contract requires external ordering.
Summary
Thread safety is an engineering property of the whole system boundary, not a single primitive. Interviews reward discussing invariants, failure injection, and testing strategy, not only naming mutex.
Deeper narrative
Thread safety is invariants preserved under all interleavings: atomicity, visibility, and ordering. Languages expose atomics with memory orders; ignoring them yields “works on my machine” races on ARM TSO differences.
Mechanism (step by step)
Identify shared state
Heap globals, caches, lazy singletons, refcounts.
Choose synchronization
Mutex for invariants; atomics for counters; RCU for read-mostly Linux kernel paths.
Document ordering
C++ memory_order_acquire/release; Java volatile happens-before.
Test
Stress + TSAN + fault injection on timeouts.
Key insights
Document contracts
Prefer immutability
Avoid fat locks
Test with stress + sanitizers
Did you know?
Common pitfalls
Check-then-act races
Use compare-and-swap or mutex around predicate + mutation.
Double-checked locking without barriers
Published partially constructed object, classic bug.
Glossary
Happens-before
Data race
RCU
Interview follow-ups
- Difference between data race and race condition?
- When is a lock-free algorithm worth the complexity?
- What does `volatile` in C guarantee vs not guarantee?
Callouts
TOCTOU
Checking then acting on shared state without holding a lock is a classic thread-unsafe pattern.
Walkthrough & deep dive
Left: practical “how would I use this?” threads. Right: slower, code-leaning explanations, open one panel at a time so the page does not feel like a wall of sameness.
Walkthrough
Spot the bug
Deep dive
Seqlocks (kernel pattern)
Readers retry if writer increments sequence, good for rarely written, often read counters.
Compile with TSAN
clang -fsanitize=thread -g prog.c -o prog
Self-check
1A data race in C/C++ without atomics is…
2Thread-safe usually means…
3Double-checked locking can fail without…