Processes & Threads
What a running program actually is — address space, the process lifecycle, and why threads are lighter.
What is a Process?
A process is a program in execution — an instance with its own address space (code, data, heap, stack), a set of registers, a program counter, and OS bookkeeping in a Process Control Block (PCB). A program on disk is passive; a process is the active, running thing.
Process States
The OS moves a process through states as it runs, waits and is scheduled. The classic five-state model:
| State | Meaning |
|---|---|
New | Being created |
Ready | Loaded, waiting for the CPU |
Running | Executing on the CPU right now |
Waiting | Blocked on I/O or an event |
Terminated | Finished; PCB about to be reclaimed |
Running at a time. The scheduler cycles Ready ⇄ Running; I/O bounces Running → Waiting → Ready.Process vs Thread
A thread is a unit of execution inside a process. Threads of one process share its address space (heap, globals, open files) but each has its own stack, registers and program counter. That sharing makes threads cheap to create and switch — and dangerous, because they can stomp on shared memory.
- Heap & globals
- Stack
| Aspect | Process | Thread |
|---|---|---|
| Address space | Private | Shared with siblings |
| Creation cost | High (fork) | Low |
| Context switch | Expensive (TLB flush) | Cheap |
| Crash blast radius | Isolated | Can take down the process |
| Communication | IPC (pipes, sockets) | Shared memory directly |
Creating a Process — fork()
On Unix, fork() clones the calling process. It returns twice: 0 in the child, the child’s PID in the parent. exec() then replaces the child’s image with a new program — the fork-exec pattern behind every shell command.
#include <unistd.h> pid_t pid = fork(); if (pid == 0) { // child: replace image with /bin/ls execlp("ls", "ls", "-l", NULL); } else { wait(NULL); // parent reaps the child }
wait()s becomes a zombie (dead but still in the table). A child whose parent dies first becomes an orphan, re-parented to init/systemd.Inter-Process Communication (IPC)
Because processes don’t share memory, they need explicit channels to talk. Common IPC mechanisms, from simplest to most flexible:
| Mechanism | Use it for |
|---|---|
| Pipes | One-way byte stream between related processes (ls | grep) |
| Named pipes (FIFO) | Same, but between unrelated processes |
| Shared memory | Fastest — a common memory region, but you must synchronize |
| Message queues | Structured, ordered messages |
| Sockets | Across machines, or local (Unix domain sockets) |
Interview Questions
Process vs thread — one sentence.
A process is an isolated program with its own address space; a thread is a lighter execution unit inside a process that shares that address space but keeps its own stack and registers.
Why does fork() return twice?
It creates a near-identical copy of the process; execution continues in both the parent and the new child from the same point, so the single call yields a return in each — 0 in the child, the child PID in the parent.
What is a zombie process and how do you avoid it?
A terminated child whose exit status hasn’t been reaped. The parent must call wait()/waitpid(); otherwise the entry lingers. In practice, handle SIGCHLD or double-fork.
Context switch — what makes it expensive?
Saving/restoring registers and PC, switching the memory map, and (for processes) flushing the TLB and cache locality. Thread switches within a process skip the address-space swap, so they’re cheaper.