Frontend Labs
⋯

Part 2 — Processes, threads, and the CPU

Part 1 established that the OS multiplexes hardware among programs that each believe they own it. This part is the first and biggest instance of that lie made concrete: what a process actually is, how one CPU is shared between many of them, and where a thread fits into that picture.

Chapter 4 — What a process actually is

In one sentence

A process is a running program plus everything the OS tracks to keep it isolated and resumable: its own memory space, its own file descriptors, and a record of exactly where it is in its own execution.

Why this matters

"How many processes can this server handle" is one of the oldest, most practical capacity-planning questions in computing, and answering it well requires knowing what a process actually costs.

How it actually works

   A process is NOT just "the code running." The kernel maintains a
   whole record for it (a "process control block") including:
     PID           a unique process ID number
     MEMORY MAP     its private virtual address space (Chapter 10)
     FILE
     DESCRIPTORS    a table of everything it has open (files, sockets,
                    pipes -- Chapter 23)
     REGISTERS      the CPU's exact state when this process was last
                    paused, so it can resume perfectly
     PARENT PID     who created it (for wait()/zombies, Chapter 3)
     PERMISSIONS     which user it runs as, what it's allowed to do
     SIGNAL HANDLERS custom behaviour for signals it's registered for
                    (Chapter 20)

   Creating a process is NOT CHEAP: the kernel has to allocate and set up
   all of the above. This cost is exactly why the industry has spent
   decades inventing lighter-weight alternatives -- threads (Chapter 7),
   thread pools, event loops, and eventually containers (Phase 3), all of
   which exist partly to avoid paying the full cost of a brand-new
   process for every unit of work.

Real-world example

   The "C10K problem" (a name coined by Dan Kegel in a widely-read 1999
   essay) asked: can a single server handle 10,000 CONCURRENT
   connections? The traditional answer at the time -- Apache's "prefork"
   model, spawning one whole OS PROCESS per incoming connection -- hit a
   hard wall well before 10,000, because each process's memory
   footprint and scheduling overhead (Chapter 8) added up brutally at
   that scale.
   This is precisely why Igor Sysoev built NGINX (first released 2004),
   using an EVENT-DRIVEN model that handles thousands of connections
   with a small, FIXED number of worker processes instead of one per
   connection -- the same instinct as this chapter's "processes aren't
   free" lesson, engineered into one of the world's most-used web
   servers. Today's async/event-loop frameworks (Node.js, async Python,
   Go's goroutines) all descend from the same realisation: for
   high-concurrency I/O-bound work, a process (or even a thread) per
   task is too expensive.

Try it yourself

# See what the kernel actually tracks for one process
echo $$                          # your shell's own PID
cat /proc/$$/status | head -20   # the kernel's own record of it
ls /proc/$$/fd/                  # its open file descriptors right now

# Estimate the real cost of a process on your machine
ps aux | awk '{sum+=$6} END {print sum/1024 " MB total RSS across all processes"}'

Common mistakes

  • Thinking a process is "just code." The kernel-tracked state (memory map, file descriptors, permissions) is just as much "the process" as the code itself.
  • Assuming more processes is always fine. Each one has real memory and scheduling overhead; "spawn a process per request" doesn't scale the way "spawn a process per user session, ever" does.
  • Confusing PID reuse with process identity. PIDs get RECYCLED after a process exits — a PID you saw an hour ago may belong to a totally different process now.

Check yourself

  1. Name four things the kernel tracks for a process, beyond "the code."
  2. Why is creating a process more expensive than, say, calling a function?
  3. What problem was NGINX's event-driven architecture specifically designed to solve?

(Answers: Appendix E.)

Further reading

  • Essay: "The C10K problem," Dan Kegel (kegel.com/c10k.html) — the original, still-relevant essay that shaped a generation of server design.
  • Book (free): OSTEP, "Processes" chapter.
  • Reference: man 5 proc — the full documentation of everything under /proc/<pid>/.

Generated from real-life-os-guide.md · 8 Oct 2026 16:36