// the one-minute version
A thread is a single flow of execution inside a process. One process can run many threads that share its memory but each own a stack and registers. Threads make programs faster on multicore CPUs and more responsive — but the shared memory that makes them fast is exactly what makes concurrency bugs possible. This chapter also separates two confused ideas: concurrency (juggling many tasks) and parallelism (literally running at once).
A single-threaded process does one thing at a time. But a browser wants to render, run scripts, and download images at once — without a whole separate process for each. The answer is threads: many lanes of execution inside one process, sharing its memory.
01 What a thread is
A thread owns its program counter, registers, and stack — but shares the process's code, heap, globals, and open files with its siblings. That sharing is the point: threads pass data through shared memory instantly, with no IPC.
Each thread owns
Program counter, CPU registers, and a stack of local variables and call frames.
Threads share
The code, heap, global variables, and open files of their process.
02 Why threads
Four classic benefits: responsiveness (one thread runs the UI while another does slow work), resource sharing (threads share memory for free, unlike processes), economy (creating a thread is far cheaper than a whole process — no new address space), and scalability (threads run on different cores in parallel).
03 Concurrency vs parallelism
These sound alike but aren't. Concurrency means dealing with many tasks all in progress — even on one core, by interleaving. Parallelism means literally executing multiple tasks at the same instant, which needs multiple cores.
04 How much can parallelism help? Amdahl's law
Throwing more cores at a program has a hard ceiling, captured by Amdahl's law: the speedup is limited by the fraction of the work that must run serially. If 25% of a job is inherently sequential, then even with infinite cores you can never go more than 4× faster — that serial quarter dominates. The lesson: parallel hardware only pays off if the algorithm is mostly parallelizable.
05 User threads vs kernel threads
User-level threads are managed by a library in user space — fast to create and switch, but the kernel sees only one process, so one blocking system call can stall them all. Kernel-level threads are managed by the OS — it can schedule them on separate cores and one block won't freeze the rest, at the cost of more overhead per operation.
06 Multithreading models
How user threads map onto kernel threads gives three classic models:
| Model | Mapping | Trade-off |
|---|---|---|
| Many-to-one | many user → 1 kernel thread | fast, but one block stalls all; no true parallelism |
| One-to-one | each user → its own kernel thread | real parallelism & isolation; more overhead per thread |
| Many-to-many | many user → smaller pool of kernel threads | flexible balance; more complex to implement |
07 Thread pools
Creating a fresh thread per task is wasteful and unbounded. A thread pool keeps a fixed set of workers alive and feeds them tasks from a queue. It caps how many threads exist (protecting against overload) and skips repeated creation cost. This is how web servers handle thousands of requests with a handful of workers.
08 The dark side: implicit threading and data races
Because threads share memory, two threads touching the same data without coordination create a race condition — a bug that depends on timing and may appear once in a million runs. Other hazards include deadlock (Chapter 8) and the difficulty of dividing work and balancing it across cores. Modern frameworks lean on implicit threading (thread pools, fork-join, OpenMP) to let the runtime manage threads so programmers make fewer of these mistakes — but the underlying dangers remain.
common catches & gotchas
- Concurrency ≠ parallelism — One core interleaves (concurrent) but never runs two things at the same instant (parallel). Mixing these up is the most common Chapter 4 error.
- Threads share the heap, not the stack — Local variables are private per thread; heap and globals are shared. Bugs come from assuming the wrong one.
- Amdahl's law caps speedup — A mostly-serial program barely benefits from more cores. Don't promise linear speedup.
- User threads can block each other — With many-to-one, one blocking system call freezes every user thread, because the kernel sees just one schedulable entity.
- More threads can be slower — Beyond core count, threads fight for the CPU and caches. Thread pools exist partly to stop this.
09 Questions students actually ask
What's the core difference between a thread and a process?
Processes have separate memory; threads in one process share memory. That makes threads cheaper and faster to coordinate, but a bug in one thread can corrupt data the others rely on.
Can I get parallelism on a single-core CPU?
No. One core runs one instruction stream at a time, so you only get concurrency (fast interleaving). True parallelism needs multiple cores.
What does Amdahl's law tell me?
Speedup from more cores is capped by the serial fraction of the work. If 25% must run sequentially, the maximum speedup is 4×, no matter how many cores you add.
Why do most systems use one-to-one threading?
It gives real multicore parallelism and keeps one blocked thread from freezing the others, and modern kernel threads are cheap enough that the overhead is acceptable.
Why use a thread pool instead of making threads on demand?
To cap the total number of threads (so a flood of work can't exhaust the system) and to avoid paying thread-creation cost repeatedly. The pool reuses a fixed set of workers.
10 Key takeaways
- A thread is a flow of execution; threads share their process's memory but own stack and registers.
- Threads add responsiveness, cheap sharing, low cost, and multicore scalability.
- Concurrency = juggling tasks; parallelism = running them at once. Different ideas.
- Amdahl's law: the serial fraction caps the speedup from more cores.
- User threads are fast but kernel-blind; kernel threads get real scheduling at more cost.
- Models: many-to-one, one-to-one (the common choice), many-to-many.
- Thread pools bound and reuse workers — but shared memory means race conditions.
11 Wrapping up
Threads are how one program uses many cores and stays responsive. The power — shared memory — is also the danger, which is why scheduling and then synchronization come next. Next up: CPU Scheduling.