TWIL #058 - Processes and Threads Are Not the Same Thing
A process is an isolated program in execution. A thread is a unit of work inside a process. The distinction determines how programs share memory, how they crash, and how fast they can switch between tasks.
- #engineering
- #software
- #operating-systems
These two terms are used interchangeably in casual conversation, but they refer to distinct OS-level concepts with real performance and reliability consequences.
Process: A process is an independent instance of a program in execution. The operating system gives each process its own isolated memory space - its own heap, stack, code segment, and data segment. It also has its own file descriptors, network sockets, and OS resources.
Key properties:
- Isolation: one process cannot directly read or write another's memory (without explicit OS mechanisms like shared memory). A crash in one process does not crash others.
- Heavier to create: spawning a process requires the OS to allocate a new memory space, copy or map resources, and initialise state.
- Communication via IPC: processes communicate through pipes, sockets, message queues, or shared memory segments - all mediated by the kernel.
Thread: A thread is a unit of execution that lives inside a process. Multiple threads in a process share the same memory space - the same heap, global variables, and open file descriptors. Each thread has its own stack and registers, but that's the extent of its private state.
Key properties:
- Shared memory: threads can read and write the same data directly. This is fast but requires synchronisation (mutexes, semaphores) to avoid race conditions - bugs where two threads modify shared data simultaneously and produce inconsistent results.
- Cheaper to create: no new memory space allocation; the OS just adds a new execution context within the existing process.
- A crash in one thread can take down the entire process - because they share memory, a corrupted pointer or unhandled exception in one thread can affect all others.
Context switching: Switching between threads of the same process is significantly cheaper than switching between processes. Switching processes requires saving and restoring memory mapping tables (the page table), flushing CPU caches, and kernel intervention. Switching threads within a process skips the memory remapping step.
The Python caveat:
In CPython (the standard Python interpreter), the Global Interpreter Lock (GIL) prevents more than one thread from executing Python bytecode at a time. For CPU-bound tasks, Python threads do not give true parallelism. The workaround is the multiprocessing module, which spawns separate processes - full memory isolation, no GIL contention, but higher overhead.
Languages like Java, Go, and Rust do not have this restriction - their threading models allow true parallel CPU execution across cores.