SwadhyAI Notes

All Operating Systems notes

Start here

Thread safety means your invariants hold under every interleaving the scheduler + hardware can produce. That requires thinking about atomicity, visibility, and ordering: not only “I added a mutex somewhere.”

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

  1. Contrast a data race with a higher-level race condition.
  2. Explain check-then-act and why it needs a mutex or CAS.
  3. State what “happens-before” gives you informally.

Hardware reality

Weak memory models (e.g. ARM) make “works on x86 laptop” a dangerous proof, use language atomics or proven patterns.

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)

Treat each step as a sentence in the story you tell on a whiteboard.
1

Identify shared state

Heap globals, caches, lazy singletons, refcounts.

2

Choose synchronization

Mutex for invariants; atomics for counters; RCU for read-mostly Linux kernel paths.

3

Document ordering

C++ memory_order_acquire/release; Java volatile happens-before.

4

Test

Stress + TSAN + fault injection on timeouts.

Key insights

Each card is a compression of the lesson, use them as spaced-repetition prompts.

Document contracts

State which methods may run concurrently; default pessimism reduces incidents.

Prefer immutability

Immutable snapshots eliminate races, functional style simplifies reasoning.

Avoid fat locks

Coarse mutexes reduce bugs but hurt scalability, profile before micro-optimizing atomics.

Test with stress + sanitizers

TSAN/Helgrind find races that code review misses, use CI gates.

Did you know?

Trivia with teeth: the kind of fact that changes how you reason about a design.
`HashMap` in Java is not thread-safe; `ConcurrentHashMap` uses finer locking/atomics.
RCU read paths can be lock-free in kernel, but writers pay synchronization cost.
Double-checked locking requires careful memory ordering in languages with weak models.

Common pitfalls

Where smart people still trip, read slowly.

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

Partial order guaranteeing visibility of writes across threads.

Data race

Concurrent unsynchronized conflicting accesses, UB in C++.

RCU

Read-copy-update, wait for quiescent states before reclaiming.

Interview follow-ups

  1. Difference between data race and race condition?
  2. When is a lock-free algorithm worth the complexity?
  3. 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

`if (!q.empty()) return q.pop();` with two threads, why unsafe?

Deep dive

Seqlocks (kernel pattern)

Readers retry if writer increments sequence, good for rarely written, often read counters.

Compile with TSAN

Terminal
clang -fsanitize=thread -g prog.c -o prog

Self-check

Misses here are cheap; misses in an interview are not. Treat wrong answers as a patch list for tomorrow.

1A data race in C/C++ without atomics is…

2Thread-safe usually means…

3Double-checked locking can fail without…