CSS Prepare

optional · CSS study notes

Threading

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).

1. What a Thread Is

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.

2. Per-Thread vs Shared Resources (the core exam fact)

Each thread has its OWNAll threads SHARE (from the parent process)
Program Counter (PC)Code / text section
Register setData section (global variables)
Stack (local variables, call frames)Heap (dynamically allocated memory)
Thread ID (TID)Open files and I/O descriptors
Thread state + prioritySignals 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.

3. Thread vs Process — Comparison

AspectProcess (heavyweight)Thread (lightweight)
Address spaceOwn, fully independentShared with sibling threads
Creation costHigh — new PCB, page tables, file descriptor tableLow — only PC, registers, stack allocated
Context switchExpensive — address space switch, TLB flushCheap — no address-space change if same process
CommunicationNeeds explicit IPC (shared memory, message passing)Direct, via shared variables
ProtectionIsolated — one crash can't corrupt anotherNo isolation — one bad pointer corrupts the whole process
Synchronization needOnly where memory is deliberately sharedConstant — 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.

4. Benefits of Multithreading (four standard headings)

  1. Responsiveness — a program keeps serving the user even while one thread blocks on a long operation (the UI thread stays alive while a download thread waits on I/O).
  2. Resource sharing — threads share memory and files by default; no shmget-style setup, no kernel-mediated message passing.
  3. Economy — allocating and context-switching a thread is far cheaper than a process, because almost no new state is created.
  4. Scalability / parallelism — a multithreaded process can genuinely run on several cores at once; a single-threaded process cannot, no matter how many cores exist.

5. User-Level vs Kernel-Level Threads

AspectUser-level threads (ULT)Kernel-level threads (KLT)
Managed byA user-space thread library; kernel is unaware of themThe OS kernel directly
Switching speedVery fast — no mode switch into the kernelSlower — every switch is a system call / mode switch
Blocking behaviourOne blocking system call blocks the ENTIRE processOnly the calling thread blocks; siblings continue
True parallelismNot possible on its own — kernel schedules one entityPossible — each thread schedulable onto a separate core
PortabilityHigh — implemented purely as a libraryDepends on OS support

Only kernel threads are schedulable onto physical cores. This single fact answers every "how many threads can run in parallel?" numerical.

6. Multithreading Models

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
ModelMappingStrengthWeakness
Many-to-OneMany user threads → one kernel threadVery efficient thread management in user spaceOne blocking call blocks all threads; no multicore parallelism (e.g. Green Threads)
One-to-OneEach user thread → its own kernel threadTrue concurrency; a blocked thread doesn't block othersThread creation cost is a kernel operation, so the number of threads is usually capped (Linux, Windows)
Many-to-Many (M:N)m user threads multiplexed onto n kernel threads, n ≤ mApplication can create as many threads as it likes; kernel-thread count tuned to coresComplex to implement in the library and the kernel
Two-LevelMany-to-Many, plus the option to bind one user thread permanently to one kernel threadFlexibility of M:N with guaranteed service for critical threadsSame implementation complexity

Worked numerical pattern (2025-style): A process has 10 user threads mapped onto 2 kernel threads, on an 8-core machine. Maximum threads running in parallel? → 2. The core count and user-thread count are both distractors; the bottleneck is the number of kernel threads, because only those are schedulable.

7. Thread Libraries

  • POSIX Pthreads — a specification (IEEE 1003.1c), not an implementation; may be provided as user-level or kernel-level. Standard on UNIX/Linux/macOS. Key calls: pthread_create(), pthread_join(), pthread_exit().
  • Windows threads — a kernel-level library implementing the one-to-one model.
  • Java threads — managed by the JVM, but in practice mapped onto the host OS's thread model; created by extending Thread or implementing Runnable.

8. Threading Issues (a standard short-note question)

  1. fork() and exec() semantics — should fork() duplicate all threads of the process, or only the calling thread? UNIX offers both versions; if exec() is called straight after, duplicating all threads is wasted work since the whole image is replaced anyway.
  2. Signal handling — to which thread should a signal be delivered: the one that caused it, every thread, a designated thread, or a specific one? Synchronous signals (e.g. divide-by-zero) go to the causing thread; asynchronous ones (e.g. Ctrl-C) go to any thread not blocking that signal.
  3. Thread cancellation — terminating a thread before it finishes. Asynchronous cancellation kills it immediately (risking leaked resources or a half-updated shared structure); deferred cancellation lets the target check a flag at safe cancellation points and exit cleanly — deferred is the safer, preferred approach.
  4. Thread-local storage (TLS) — per-thread data that survives across function calls, distinct from local variables (which vanish on return) and from shared globals.
  5. Thread pools — create a fixed set of worker threads at startup and hand them tasks from a queue, instead of spawning a thread per request. Bounds resource consumption and removes creation latency from the critical path.

9. Concurrency vs Parallelism

Concurrency = multiple tasks make progress in overlapping time periods (possible on a single core via interleaving). Parallelism = multiple tasks execute at literally the same instant (requires multiple cores). A single-core machine can be concurrent but never parallel — examiners test this distinction directly.

  • Data parallelism: the same operation applied to different subsets of the same data across cores.
  • Task parallelism: different threads performing different operations, possibly on the same data.

Amdahl's Law: speedup is capped by the serial fraction S of a program — speeduplefrac1S+frac1−SNspeedup \\le \\frac{1}{S + \\frac{1-S}{N}} for N cores. With 25% serial code, even infinite cores give at most 4× speedup. Quote this whenever a question asks about the limits of adding cores.


🎯 CSS Exam Angle

Thread questions come in two shapes: (a) a comparison — thread vs process, ULT vs KLT, concurrency vs parallelism — best answered with a table plus one closing sentence on the trade-off; and (b) a small numerical on the threading model, where the answer is always the kernel-thread count, not the core count or user-thread count. For "benefits of multithreading", name the four standard headings (responsiveness, resource sharing, economy, scalability) and give a one-line example against each rather than writing a paragraph.

📌 Past CSS Paper Frequency

YearQuestionMarks
2022Thread vs process — resources created for each4
2025Threading-model parallelism (user threads on kernel threads)Numerical
MCQ-recurringWhich resource is NOT shared between threads of a process? (Ans: the stack)1

⚠️ MCQ Traps

  • The stack is NOT shared between threads, but the heap IS. This is the single most-asked thread MCQ and the most commonly reversed answer.
  • Thread creation is cheap because it shares the address space — not because a thread "does less work" or "runs faster."
  • Pthreads is a specification, not an implementation — so "Pthreads are always user-level threads" is false.
  • Many-to-One gives no true parallelism even on a multicore machine — the kernel only sees one schedulable entity.
  • A blocking system call blocks the whole process under ULT, but only one thread under KLT — this is the deciding difference in almost every ULT/KLT question.
  • Concurrency ≠ parallelism — a single-core system running ten threads is concurrent, not parallel.
  • Deferred cancellation, not asynchronous, is the safe default — asynchronous cancellation can leave shared data in an inconsistent state.

📜 Past-Paper Questions & MCQs (CSS 2016–2026)

2022 · Paper-II · Q3(c) · 4 marks

Q. What resources are used when a thread is created? How do they differ from those used when a process is created?

Ans.

  • Thread creation needs only its own thread control block, stack, program counter and register set (and thread-local storage). It shares the code, data, heap, open files and address space of its process.
  • Process creation needs a new address space (page tables), PCB, memory for code, data, heap and stack, a file table and other resources, and the OS must set all of these up.
  • Difference: a thread is "lightweight". It is faster to create and to switch (no change of address space), and threads share data easily. A process is "heavyweight" and well isolated. A fault in one thread can affect the whole process, while a process crash is contained.