Chapter 7 — Threads: sharing everything except the stack
In one sentence
A thread is a separate, independently-scheduled sequence of execution that lives INSIDE a process and shares that process's memory with every other thread in it — which makes threads cheaper than processes and dramatically easier to get wrong.
Why this matters
"Thread-safe" and "race condition" (Chapter 17) are two of the most common words in any serious engineering discussion, and they only make sense once you know exactly what threads do and don't share.
How it actually works
A PROCESS can contain ONE OR MORE threads. All threads in the same
process share:
- the same memory (global variables, heap allocations)
- the same open file descriptors
- the same process ID (from the OS's perspective, mostly)
Each thread gets its OWN:
- stack (local variables, function call history)
- CPU register state / program counter (where THIS thread currently
is in the code)
- thread ID
WHY THIS MATTERS SO MUCH: because threads share memory, TWO THREADS
CAN TOUCH THE SAME VARIABLE AT THE SAME TIME -- something two
separate PROCESSES simply cannot do by accident, because their
memory is isolated (Chapter 10). This is BOTH the main reason threads
are useful (fast communication, no copying needed, no fork() cost)
AND the main reason threaded code is notoriously hard to get right
(Chapter 17's race conditions, Chapter 18's locks).
THREADS VS. PROCESSES, the trade-off in one table:
PROCESSES isolated (safer), heavier to create, communicate via
slower IPC mechanisms (Chapter 19)
THREADS share memory (faster, riskier), cheap to create, need
explicit synchronisation (Chapter 18) to be safe
Real-world example
Node.js was DELIBERATELY built single-threaded for its JavaScript
execution (I/O is handled separately, under the hood, via a thread
pool and an event loop) -- a choice its creator, Ryan Dahl, explained
publicly in his original 2009 talks introducing the project. The
explicit reasoning: multi-threaded programming with shared mutable
state is HARD TO GET RIGHT (exactly this chapter's warning), and for
I/O-heavy server workloads, an event-driven single-threaded model
sidesteps an entire category of race-condition and locking bugs
almost entirely, at the cost of needing a different mental model
(callbacks/promises/async-await) for writing non-blocking code.
This is a genuinely influential, still-debated design choice
(Debated: many engineers argue Node's model trades one kind of
complexity for another, "callback hell" or now `async`/`await`
chains) -- but it's a real, deliberate illustration of "threads are
powerful but dangerous enough that entire platforms are designed
specifically to minimise their use."
Try it yourself
# See threads vs processes on your own machine right now
ps -eLf | wc -l # count of THREADS across the whole system
ps aux | wc -l # count of PROCESSES
# Pick one multi-threaded process and see its thread count
pgrep -f firefox 2>/dev/null | head -1 | xargs -I{} cat /proc/{}/status 2>/dev/null | grep Threads
# or, if you don't have firefox running, try:
cat /proc/self/status | grep Threads # your shell has how many?
Build it in Go
Goroutines are Go's answer to "threads are expensive". In a measured run,
20,000 goroutines (sleeping or blocked on sockets) used 16 OS threads,
while 100 goroutines blocked in raw read(2) calls pushed it to 108. See
Chapter 73 for the lab, and the
Go guide's scheduler chapter for how the runtime maps
goroutines onto threads.
Common mistakes
- "Threads are always faster than processes." For CPU-bound, isolated work, processes (which can run on separate cores, same as threads can) are often simpler and just as fast — threads win specifically when you need fast, frequent shared-memory communication.
- Assuming shared memory means synchronised access. The OS guarantees threads CAN see the same memory; it guarantees NOTHING about the order or safety of concurrent access — that's entirely on you and your locks (Chapter 18).
- Thinking "single-threaded" means "can't handle concurrency." Node.js handles huge numbers of CONCURRENT connections single-threadedly, via the event loop — concurrency and threading are related but distinct ideas (§0.4).
Check yourself
- What do threads in the same process share, and what does each thread keep private?
- Why are threads cheaper to create than processes?
- Why did Node.js's creator choose a single-threaded model for JavaScript execution?
Further reading
- Book (free): OSTEP, "Concurrency" chapters (the introduction through locks) — the best treatment of why threading is hard, and how to do it safely.
- Talk: Ryan Dahl's original Node.js introduction talk (2009, JSConf) — the actual reasoning, from the source.
- Reference:
man 7 pthreads— the POSIX threads API reference.