Processes vs Threads
What separates a process from a thread, what they share, what they cost to create and switch, and when to pick each. Includes a runnable test showing a thread changing parent memory and a process not.
A process is a running program with its own private virtual address space, while a thread is a unit of execution inside a process that shares the process's code, heap, globals and open files. Interviewers expect the trade-off: threads are cheaper to create and switch but can corrupt shared data, while processes are isolated but need IPC.
A process is a running program with its own private address space. A thread is a unit of execution inside a process, and all threads in a process share its memory and open files. Threads are cheaper to create and switch, but they can corrupt each other's data. Processes are isolated, but communication is harder.
- Threads of the same process share code, heap, global variables and open files, while each thread has its own stack, registers and program counter.
- A context switch between threads of the same process skips the address-space switch, so cached TLB translations stay valid and the switch is cheaper.
- On Linux, fork() creates a child process as a copy-on-write copy of the parent, while clone() creates a task that shares the address space.
- If one thread crashes with a fatal error such as a bad memory access, the whole process usually dies, while a crashed process leaves other processes running.
- In standard CPython the global interpreter lock lets only one thread run Python bytecode at a time, so CPU-bound work needs multiple processes or native extensions.
01Process: a program in execution
A program on disk is just a file. When you run it, the OS creates a process: it loads the code, sets aside memory for the stack and heap, gives it a process ID (PID) and starts running it. The OS keeps a record for each one called the process control block (PCB). It holds the PID, the saved CPU registers, the state, the memory map and the list of open files.
Each process has its own virtual address space. Address 0x1000 in process A and address 0x1000 in process B point to different physical memory. One process cannot read or overwrite another's memory by accident, and that isolation is the main thing a process buys you.
A process is usually in one of a few states: new, ready (waiting for a CPU), running, waiting (blocked on I/O or a lock), or terminated.
02Thread: a path of execution inside a process
A thread is the smallest unit the scheduler runs. Every process starts with one thread, and can create more. Threads of the same process share the code, the heap, global variables and open files. Each thread has its own program counter, registers and stack, because it needs its own place to keep local variables and return addresses.
Sharing is the point. A web server can handle many requests with threads that all read the same cache in memory, without copying it. It is also the danger. Two threads that write the same variable without coordination produce a race condition, which the topic on mutexes and semaphores covers.
03Seeing the difference in code
import threading, multiprocessing as mp
data = []
def from_thread():
data.append('thread was here')
def from_process():
data.append('child process was here')
if __name__ == '__main__':
t = threading.Thread(target=from_thread)
t.start(); t.join()
print('after thread', data)
p = mp.get_context('fork').Process(target=from_process)
p.start(); p.join()
print('after process', data)Run on Linux, this prints after thread ['thread was here'] and then after process ['thread was here']. The thread's change is visible to the parent because they share memory. The child process appended to its own copy of the list, so the parent never saw it.
On Linux a process is created with fork(), which makes a copy of the parent (using copy-on-write, so pages are only really copied when one side modifies them). Threads are created with clone(), which makes a new task that shares the address space.
04Cost: creation and context switch
A context switch saves the registers of the running task and loads those of the next one. When the next task belongs to a different process, the OS must also switch the address space, which invalidates cached address translations (the TLB, covered in the virtual memory topic) and makes the next accesses slower while those caches refill. Switching between two threads of the same process skips that.
Creating a process needs a new address space and page tables, while a thread needs mainly a stack and a small control record. So threads are cheaper to create and to switch between. How much cheaper depends on the OS and workload, so measure before you decide on that basis alone.
05Talking to each other
Because threads share memory, communication is trivial and also unsafe unless you guard it with locks.
Processes must ask the OS for a channel. The common ones are pipes (a byte stream between two processes), message queues, sockets (the same API works across machines), and shared memory (the OS maps one region into two address spaces, which is fast but needs its own locking). Signals are for short notifications such as "please stop".
A crash behaves differently too. If one thread corrupts memory or crashes, the whole process usually dies. If one process crashes, the others carry on. Browsers use a process per tab for exactly this reason.
06Choosing between them
Use threads when the tasks need to share a lot of data and you can control access to it: a server holding an in-memory cache, a UI keeping a background task alongside the main loop, a program overlapping I/O waits.
Use processes when you want fault isolation, security boundaries, or to avoid shared-state bugs. Chrome's sandboxing, and worker pools in many servers, work this way.
A Python-specific note: in standard CPython the global interpreter lock (GIL) lets only one thread run Python bytecode at a time. Threads still help with I/O-bound work, since a thread waiting on the network releases the lock, but for CPU-bound work you need multiple processes or native extensions. Free-threaded builds (officially supported since Python 3.14, PEP 779) run threads in parallel, but they are a separate optional build, not the default.
07Common interview questions
Q: What do threads of a process share, and what is private?
A: They share code, heap, globals and open files. Each has its own stack, registers and program counter.
Q: Why is a context switch between threads cheaper?
A: No address-space switch, so cached translations stay valid and less state is saved.
Q: What happens when a process calls fork()?
A: The OS creates a child that is a copy of the parent with a different PID. Pages are shared copy-on-write until one side writes.
Q: What is a zombie process?
A: A child that has finished but whose exit status the parent has not yet collected with wait(). It holds only a process table entry.
Q: What is an orphan process?
A: A process whose parent exited first. It gets adopted by init (PID 1) or a subreaper.
Q: Can one thread crash the whole program?
A: Yes. Threads share one address space, so a fatal error such as a bad memory access takes down the process.