CSS Optional — Paper-II, Section-A · P-II.III · Listed as a standalone topic in the CS-for-CSS book's OS chapter. [Process Management] covers threads only as one section; this page is the full treatment — models, libraries, and threading issues — since thread-vs-process and threading-model questions appear in their own right (2022, 2025).
A thread is the basic unit of CPU utilization — the smallest sequence of instructions the scheduler can dispatch independently. A process is the container (address space + resources); a thread is a path of execution inside that container. A traditional (heavyweight) process has exactly one thread; a multithreaded process has several threads sharing one address space.
Motivation: most real applications are naturally parallel — a word processor simultaneously accepts keystrokes, renders the display, and runs a spell-checker. Creating a separate process for each of these would mean three address spaces and expensive IPC; three threads share one address space and communicate through ordinary variables.
| Each thread has its OWN | All threads SHARE (from the parent process) |
|---|---|
| Program Counter (PC) | Code / text section |
| Register set | Data section (global variables) |
| Stack (local variables, call frames) | Heap (dynamically allocated memory) |
| Thread ID (TID) | Open files and I/O descriptors |
| Thread state + priority | Signals and signal handlers |
The single sentence to memorize: threads share code, data, heap and files; they keep their own PC, registers and stack. Almost every thread-vs-process question can be answered from this line plus its consequences.
| Aspect | Process (heavyweight) | Thread (lightweight) |
|---|---|---|
| Address space | Own, fully independent | Shared with sibling threads |
| Creation cost | High — new PCB, page tables, file descriptor table | Low — only PC, registers, stack allocated |
| Context switch | Expensive — address space switch, TLB flush | Cheap — no address-space change if same process |
| Communication | Needs explicit IPC (shared memory, message passing) | Direct, via shared variables |
| Protection | Isolated — one crash can't corrupt another | No isolation — one bad pointer corrupts the whole process |
| Synchronization need | Only where memory is deliberately shared | Constant — sharing is the default (see [Process Synchronization]) |
The trade-off to state in an answer: threads buy speed and easy sharing at the cost of protection. Chrome deliberately uses a process per tab rather than a thread, precisely so one tab's crash cannot take down the browser.
shmget-style setup, no kernel-mediated message passing.| Aspect | User-level threads (ULT) | Kernel-level threads (KLT) |
|---|---|---|
| Managed by | A user-space thread library; kernel is unaware of them | The OS kernel directly |
| Switching speed | Very fast — no mode switch into the kernel | Slower — every switch is a system call / mode switch |
| Blocking behaviour | One blocking system call blocks the ENTIRE process | Only the calling thread blocks; siblings continue |
| True parallelism | Not possible on its own — kernel schedules one entity | Possible — each thread schedulable onto a separate core |
| Portability | High — implemented purely as a library | Depends on OS support |
Only kernel threads are schedulable onto physical cores. This single fact answers every "how many threads can run in parallel?" numerical.
graph TD
subgraph "Many-to-One"
U1["User threads"] --> K1["1 Kernel thread"]
end
subgraph "One-to-One"
U2["User thread"] --> K2["Kernel thread"]
end
subgraph "Many-to-Many"
U3["m User threads"] --> K3["n Kernel threads (n <= m)"]
end