Module 2 · Unit 4 of 5
Threads
A thread is a unit of execution inside a process — a lighter-weight abstraction that shares code, data, and file descriptors with other threads in the same process. This unit examines why threads exist, how they are implemented, and how they change the way we structure concurrent programs.
Module 2 · Unit 4
Threads
Threads let a single process perform several tasks at once. This unit explains why that is useful, how different threading models are implemented, and how to write POSIX-threaded programs.
01 Unit learning outcomes
Upon completion of this unit you will be able to
- U4.1 — Explain multithreading.
- U4.2 — Compare threading models.
- U4.3 — Analyse multicore concurrency.
- U4.4 — Develop POSIX-thread programs.
- U4.5 — Evaluate thread-management strategies.
This unit addresses course learning outcomes CLO2 and CLO6.
02 Lessons in this unit
The first lesson motivates threads. Lessons 4.2 and 4.3 contrast the two major implementation strategies. Lesson 4.4 examines how threads exploit multiple CPU cores. Lesson 4.5 gives you the POSIX API you will use throughout the course.
Why Threads?
The problems threads solve, the cost they impose, and when a process is the better abstraction.
Lesson 4.2User Threads
Threads managed by a library, invisible to the kernel; how they work and what they sacrifice.
Lesson 4.3Kernel Threads
Threads scheduled by the kernel; the cost, the benefit, and the models that combine both.
Lesson 4.4Multicore Processing
True parallelism, cache coherence, memory models, and the limits of thread-level scaling.
Lesson 4.5POSIX Threads
The pthreads API: creating, joining, and managing threads with the standard C interface.
03 What you will learn, lesson by lesson
4.1 Why Threads?
- Define a thread.
- Explain why threads exist.
- Compare threads and processes.
- Identify thread benefits.
- Analyse thread costs.
4.2 User Threads
- Define user-level threads.
- Describe library-based scheduling.
- Explain blocking problems.
- Analyse performance trade-offs.
- Evaluate user-thread use cases.
4.3 Kernel Threads
- Define kernel-level threads.
- Describe kernel thread scheduling.
- Compare threading models.
- Analyse system-call costs.
- Evaluate implementation strategies.
4.4 Multicore Processing
- Explain true parallelism.
- Describe cache coherence.
- Analyse memory models.
- Evaluate scaling limits.
- Measure parallel speedup.
4.5 POSIX Threads
- Create threads with
pthread_create. - Join threads with
pthread_join. - Manage thread attributes.
- Handle thread errors.
- Write correct multithreaded code.
04 Worked example
Two ways to compute a sum in parallel. Both compute the same result; they differ in cost.
Process-based
/* Each child computes a partial sum
and returns it via a pipe. */
pid_t p1 = fork();
/* ... repeat for each chunk ... */
/* Parent reads each pipe and sums. */
fork duplicates the address space. Data must be
marshalled through pipes or shared memory. Setup cost is high.
Thread-based
/* Each thread computes a partial sum
and writes to shared memory. */
pthread_t t[N];
for (i = 0; i < N; i++)
pthread_create(&t[i], NULL,
worker, &args[i]);
for (i = 0; i < N; i++)
pthread_join(t[i], NULL);
The address space is shared. Results are exchanged through memory. Setup cost is low, but accesses to shared state must be synchronised.
Which is right for which workload?
- Processes are better when isolation matters. A crash in one process does not take down the others. A web server that forks a handler per connection benefits from this isolation: a buggy request handler cannot corrupt the scheduler.
- Threads are better when sharing is the point. A video decoder that splits frames across cores wants to write into a shared output buffer. Threads make that natural; processes would require shared memory and explicit synchronisation.
- Threads have lower startup cost. Creating a thread does not require duplicating the address space or copying page tables. For a workload that spawns many small tasks, this matters.
- Threads have higher coordination cost. Because they share memory, threads must be carefully synchronised. This is the subject of Unit 6 — and the source of the most difficult bugs in systems programming.
05 Required reading
- OSTEP — Chapter 26, Concurrency: An Introduction, and Chapter 27, Interlude: Thread API.
- Operating System Concepts — Chapter 4, Threads and Concurrency.
-
Man pages:
pthread_create(3),pthread_join(3),pthread_attr_init(3).
06 Unit discussion
Discussion prompt
Modern programming languages offer very different concurrency primitives. Java and C# have threads with shared memory; Go has goroutines with channels; Erlang has processes with message passing and no shared state.
Choose one of these approaches and argue whether it makes concurrent programming fundamentally easier or merely shifts the difficulty elsewhere. Support your argument with a concrete example of a bug that is easy to write in one model and hard in another.
Post your response to the Unit 4 discussion forum and reply to at least two classmates. Supports CLO2, CLO6, and CLO8.
07 Laboratory connection
Lab 3 — POSIX Threads is completed at the end of this unit. You will write threaded C programs, measure their performance against a single-threaded baseline, and observe what happens when they touch shared state without synchronisation.
| Lesson | Lab 3 exercise |
|---|---|
| 4.1 Why Threads? | Baseline: single-threaded matrix multiply |
| 4.2–4.3 Thread models | Observe threads with ps -L and /proc/<pid>/task |
| 4.4 Multicore | Measure speedup with 1, 2, 4, 8 threads |
| 4.5 POSIX Threads | Implement and test a threaded work-queue |
Prepare for the race
One of the Lab 3 exercises deliberately introduces a data race so you can observe non-determinism. Do not skip it. Seeing a correct program give the wrong answer is the fastest way to appreciate why Unit 6 exists.
08 Knowledge check & quiz
Quick check before you begin
Question 1
What do threads in the same process share, and what does each thread have of its own?
Show answer
Question 2
What is the fundamental limitation of pure user-level threads that kernel-level threads do not have?
Show answer
Question 3
Why does adding more threads not always make a program faster?