What goes wrong if you start 200 whole programs to take 200 requests at once? Instead of renting a separate office per customer, share one office and simply add more people who can sit at the counter.
See this first in FoundationsCan a computer do something else while it waits?Say a web server must handle 200 requests at once. A process per request means 200 memory spaces and OS-mediated messaging for every shared piece of data — far too expensive. Hence threads: share the memory, multiply only the flows of execution.
Threads in one process share the heap, the code and open files, but each keeps its own stack — necessarily, since each is inside a different function with its own locals and return addresses. Creating a thread is roughly "one more stack plus one more context", far cheaper than a process.
To the OS a thread is Running (owns the CPU), Ready (could run, waiting its turn), or Waiting (asleep on IO). Chapter 7's waiting is Waiting, and chapter 6's context switching was really moving between these states.
This is the most misunderstood point in the series. Waiting threads are not scheduling candidates at all, which is why "the server accepts nothing yet CPU is 10%" is a real situation. The blockage is not the CPU; every thread is simply asleep.
Sharing a heap is convenient and dangerous. If two threads modify the same variable, results depend on exactly when the switch happened, so they can differ run to run. That is a race condition, and it is why locks exist.
Creating a thread is far cheaper than creating a process, but it is not free. Each thread needs its own stack (conventionally a few hundred KB up to 1 MB), and as thread counts grow the kernel run queue lengthens and scheduling itself slows down. Thousands of threads are practical; tens of thousands are not. That ceiling is the heart of the C10K story later on.
Shared memory needs locks to be safe. A lock buys correctness by selling parallelism: only one thread may be inside the guarded section, so the longer that section runs, the longer everyone else simply queues. Hold locks briefly — and waiting on IO while holding one is almost always the beginning of an incident.
Try it in the simulator
Terms in this chapter
Why it evolved this way
Threads exist precisely because of process costs: cheap creation, easy sharing, light switches. The price is isolation — one thread can take the whole process down.
Blocking = leaving the CPU (Waiting), not using it.
The remaining problem
Switching got cheaper — but does adding threads always help? →