ReviseAlgo Logo

Concurrency & Multi-threading

Processes vs Threads

Master the operating system level differences between processes and threads, comparing virtual memory layouts, context switching costs, and communication boundaries.

Last Updated: June 26, 2026 23 min read

Every execution path on your computer runs inside either a Process or a Thread. Understanding how operating systems manage these two units of execution—specifically their memory boundaries, isolation levels, and communication overhead—is a foundational requirement for low-level system design.

1. Learning Objectives

  • Differentiate between processes (isolated memory) and threads (shared memory).
  • Analyze virtual memory mapping, page tables, and Translation Lookaside Buffer (TLB) invalidation during context switches.
  • Compare Inter-Process Communication (IPC) with Inter-Thread Communication (ITC) methods and performance.
  • Evaluate the reliability and fault tolerance trade-offs of multi-processing versus multi-threading.
  • Measure context switching latency differences between processes and threads.

2. Problem & Naive Solution

Suppose you are building a web scraping crawler. The scraper needs to download 1,000 pages and parse their HTML. The page download is I/O-bound (network latency), while parsing is CPU-bound.

The Naive Solution (Processes for everything)

A developer decides to use the OS command line tool to launch a brand new process for *each* download task, executing curl or wget in a loop:

3. Issues with the Naive Approach

  • Huge Resource Overhead: Spawning a process requires allocating virtual memory space, creating new page tables, and loading executable binaries. Spawning thousands of processes will quickly exhaust system RAM.
  • Slow Context Switching: The OS must switch page directories and flush cache lines (TLB cache) when changing processes, causing massive context switching delays.
  • Complex Communication: Because processes have isolated address spaces, passing downloaded HTML data back to the main aggregator process requires heavy IPC mechanisms (pipes, sockets, or shared memory).

4. Memory Layout Comparison

A process contains its own text, data, and heap. Sibling threads nested inside a process share this heap but maintain private stacks and program counters.

5. Theory: OS Virtual Memory, TLB & Context Switching

Let's explore the core OS and hardware-level differences between processes and threads:

A. OS Address Spaces & Isolation

  • Processes (Heavyweight): Possess their own virtual-to-physical memory mapping (Page Table). If Process A attempts to write to an address belonging to Process B, the CPU MMU (Memory Management Unit) throws a Segment Fault (SegFault), blocking cross-process corruption. This ensures high fault isolation.
  • Threads (Lightweight): Share the same page table. If Thread 1 crashes with a NullPointer or memory exception, it can corrupt shared heap references, crashing all threads inside the process.

B. Context Switch Overhead: Process vs. Thread

A context switch requires changing CPU execution states:

  • Thread Context Switch: The CPU swaps register states, stack pointer (SP), and the program counter (PC). The page directory reference remains unchanged. This is fast (typically < 1-2 microseconds).
  • Process Context Switch: In addition to register swapping, the CPU must switch the active page directory (CR3 register in x86). This invalidates the Translation Lookaside Buffer (TLB)—the hardware cache mapping virtual addresses to physical RAM. The CPU must perform slow RAM lookups to rebuild the cache, degrading execution performance.

C. Communication Boundaries (IPC vs. ITC)

  • Inter-Process Communication (IPC): Requires OS-level mechanisms because processes are isolated. Includes Pipes (standard input/output redirection), Unix Domain Sockets, Message Queues, and Shared Memory segments. IPC involves system calls and context switches, making it relatively slow.
  • Inter-Thread Communication (ITC): Fast because threads share variables on the heap directly. However, they require synchronization (locks, volatiles) to prevent concurrent write corruption.

6. Syntax Explanation

To implement multiprocessing or multithreading, we use core runtime classes:

  • Java: Launching processes is managed by ProcessBuilder. Threads are instantiated by passing Runnable functional structures to Thread.
  • Python: Provides multiprocessing.Process for process-level isolation (allocating separate memory maps) and threading.Thread for shared heap threading.
  • C++: Creating threads uses std::thread. Spawning subprocesses in native Unix systems uses fork() and execvp(), requiring manual file descriptor routing.

7. Step-by-Step Implementation

  1. Determine Execution Boundaries: Identify if the task requires process-level isolation (e.g., executing third-party binaries) or thread-level speed.
  2. Spawning Processes: Configure argument lists, route input/output streams, and call startup triggers.
  3. Spawning Threads: Wrap tasks in thread objects and invoke execution.
  4. Manage Lifecycles: Wait for subprocesses (waitFor()) or threads (join()) to complete.

8. Complete Code (Process Spawning vs. Thread Execution)

This program compares spawning a separate process (launching a system ping) and spawning a concurrent thread within the application.

9. Code Walkthrough

  • Process Creation Overhead: The process example calls external ping binaries (ProcessBuilder, subprocess.run, std::system). This requires the OS kernel to verify file permissions, duplicate virtual memory pages, and establish standard file descriptors, which takes significantly longer than creating a thread.
  • Shared Memory Thread Execution: The thread example targets a local lambda function or worker method. Because it runs within the caller's memory mapping, the OS does not create new page tables, resulting in much faster execution.

10. Execution Flow

  1. Process Fork Initiated: The parent process requests memory allocation from the OS kernel.
  2. Page Table Duplication: The OS kernel duplicates page table mappings and marks physical RAM pages as Copy-on-Write (COW).
  3. Execution Swap (TLB Flush): The CPU switches the active page directory register to point to the new process's page table. The TLB is flushed.
  4. Execution Complete: The child process exits, and the kernel triggers an interrupt to notify the parent thread.

11. Complexity Analysis

  • Time Complexity:
    • Process Context Switch: $O(\text{Pages})$ since virtual memory mapping registers must be swapped and the TLB is invalidated.
    • Thread Context Switch: $O(1)$ registers swap.
  • Space Complexity:
    • Process allocation: $O(\text{Address Space})$ requiring virtual memory structures.
    • Thread allocation: $O(1)$ fixed stack allocation (typically 1MB).

12. Best Practices

  • Use Processes for Isolation: Run unsafe, third-party executables or scripts in separate processes. If the script crashes or leaks memory, the main application remains unaffected.
  • Use Threads for High-Throughput I/O: Use threads for tasks like handling API requests or network connections, where speed and shared memory access are critical.

13. Common Mistakes

  • Failing to Clean Up Zombie Processes: Forgetting to call waitFor() or read exit statuses on spawned processes. This prevents the OS from cleaning up the process table, leaving "zombie" entries that exhaust system resources.
  • Sharing Mutable Data Without Locks: Sharing memory between threads without synchronization, causing data corruption due to race conditions.

14. Interview Discussion

Q: What is Copy-on-Write (COW) and how does it optimize process spawning?
Answer: When a process is spawned using fork(), the OS does not copy the entire physical memory immediately. Instead, both parent and child processes share the same physical memory pages. The pages are marked as read-only. If either process attempts to write to a page, the CPU raises an interrupt, and the OS copies that specific page to a new location in RAM. This makes process creation much faster and saves memory.
Q: What happens to a thread if its parent process receives a SIGKILL signal?
Answer: Threads cannot exist without a parent process. If the parent process is killed, all of its threads are terminated immediately by the OS kernel, and their allocated memory (both heap and stacks) is freed.
Q: What is the purpose of the Translation Lookaside Buffer (TLB)?
Answer: The TLB is a high-speed hardware cache on the CPU that stores recent virtual-to-physical memory address translations. It avoids the need to perform slow multi-level page table lookups in RAM during memory accesses.

15. Practice Exercises

  • Easy: Write a program that spawns a thread and prints the thread ID along with the process ID. Compare the process IDs of the main and worker threads.
  • Medium: Write a Python script that benchmarks the time taken to spawn 100 threads versus 100 subprocesses.
  • Hard: Build a basic Inter-Process Communication system using shared memory files (mmap) to pass data between two separate Python processes.

16. Challenge Problem

Design an OS-level Task Isolation Hub. The hub takes custom Java code snippets as strings, compiles them, and runs them. To prevent user snippets from freezing the hub (e.g., via infinite loops or memory leaks), execute each snippet in an isolated subprocess. Set a 5-second timeout on the subprocess. If a snippet times out or crashes, terminate the subprocess without crashing the main application.

17. Summary & Cheat Sheet

Feature Process Thread
Memory Space Isolated (private address space) Shared (shares heap with sibling threads)
Context Switch Cost High (requires flushing TLB and changing page tables) Low (only requires swapping register values)
Communication Slow IPC (sockets, pipes, shared memory) Fast ITC (shares heap variables directly)
Fault Tolerance High (crashes do not affect other processes) Low (a crash in one thread can crash the entire process)

18. Quiz

1. Which execution unit has its own private virtual address space and page tables?

A) Thread
B) Process (Correct)
C) Green Thread

2. Why is a process context switch slower than a thread context switch?

A) Because processes do not use RAM
B) Because the CPU must switch page directories, invalidating the TLB cache (Correct)
C) Because threads run faster than CPU clocks

3. Sibling threads within the same process share access to which memory region?

A) Private stack
B) Heap (Correct)
C) CPU registers

4. What happens when a thread performs a segment fault memory error?

A) The OS restarts only that thread
B) The entire parent process (along with all sibling threads) terminates (Correct)
C) The CPU reboots

5. Which of the following is a fast communication method between threads?

A) Sockets
B) Modifying shared heap variables directly (Correct)
C) Pipes

6. What optimization allows the OS to delay copying memory pages when spawning a new process?

A) Page faulting
B) Copy-on-Write (COW) (Correct)
C) Preemptive caching

7. What is a "zombie process"?

A) A process that runs forever
B) A terminated process whose exit status has not yet been read by its parent (Correct)
C) A crashed thread

8. Which CPU component handles virtual-to-physical address translation cached in the TLB?

A) ALU
B) MMU (Memory Management Unit) (Correct)
C) Control Unit

9. Spawning a thread requires allocating virtual memory for its private:

A) Heap
B) Call stack (Correct)
C) Static globals

10. Which is a characteristic of Inter-Process Communication (IPC)?

A) It does not require system calls
B) It is used to communicate across isolated memory boundaries (Correct)
C) It is always faster than inter-thread communication

19. Next Lesson Preview

In the next lesson, we will cover the Thread Lifecycle & States. We will study the states a thread transitions through (NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED) and how scheduler triggers control them!