ECE344 Fall 2026 (Sec 1) Lec 13 - Threads
Watch on YouTube →
Overview
Jon Eyolfson distinguishes concurrency—switching among tasks—from parallelism—running tasks simultaneously, then explains how threads add multiple execution contexts inside one process. Using POSIX Pthreads, he demonstrates thread creation, scheduling, joining, detaching, exit behavior, stack attributes, and why passing a pointer to a short-lived stack variable can produce incorrect thread arguments.
Key takeaways
- Concurrency and parallelism are different properties: a single CPU can interleave tasks, while simultaneous execution requires multiple processing units.
- Threads share a process’s virtual memory and resources, but each has independent registers and a stack; this makes shared data convenient to access and easier to misuse.
- Creating and switching between threads in one process can be cheaper than using separate processes because threads reuse the same address space and page tables.
- `pthread_join` waits for one specified joinable thread and collects its return value; detached threads instead release resources automatically when they finish.
- Returning from `main` terminates the entire process, whereas `pthread_exit` ends only the calling thread and lets other live threads continue.
- A pointer to a creator’s loop-local stack variable is unsafe as a thread argument when that variable can change or go out of scope; heap allocation can provide storage with a suitable lifetime.
Chapters
0:00
Course Transition: From Test One to Threads
- Jon Eyolfson moves from the completed first test to threads as the next operating-systems topic.
- The test is still being graded, with a possible discussion planned for Tuesday.
3:25
Concurrency Versus Parallelism Through Everyday Tasks
- Concurrency means switching among tasks to make progress; a single CPU can do this through context switching.
- Parallelism means executing independent tasks at the same instant, typically using multiple CPU cores.
- Eating and gesturing can be parallel but not concurrent under the example’s rule that eating cannot be interrupted; talking and gesturing can be both.
8:47
Threads Add Execution Contexts Inside a Process
- A thread is the part of a process that executes code, with its own registers and stack.
- Threads in one process share code, globals, heap, file descriptors, and virtual memory; each thread’s stack remains independent.
- Thread-local storage gives each thread its own copy of a variable; `errno` is an example that avoids one thread’s error value confusing another.
13:21
Choosing Threads or Processes: Sharing, Cost, and Failure
- Separate processes have isolated virtual memory and communicate explicitly through IPC mechanisms such as pipes and signals; threads share memory directly.
- Creating a thread requires less work than `fork`, and switching between threads in one process can avoid changing page tables and flushing the TLB.
- A thread crash can terminate the whole process, while independent processes can fail separately; browser tabs moved to separate processes to improve crash isolation.
17:10
POSIX Pthreads and the `pthread_create` Interface
- Pthreads are included with `pthread.h` and linked with the thread option; each Pthread function has its own manual page.
- `pthread_create` takes a thread-handle destination, optional attributes, a start-routine function pointer, and one `void *` argument.
- Pthread functions return zero on success or an error number directly on failure rather than setting `errno`.
22:00
Thread Scheduling, `pthread_join`, and Program Lifetime
- After `pthread_create`, the main thread and new thread can run in either order; the example may print `in main` before or after `in run`.
- Returning from `main` calls process-wide `exit`, which ends every thread and can prevent the newly created thread from running.
- `pthread_join` blocks for a specified joinable thread, collects its pointer return value, and releases its resources; each joinable thread must be joined exactly once.
29:40
Thread Exit Semantics and Detached Threads
- Returning from a thread’s start routine acts like `pthread_exit` with that routine’s return value; `pthread_exit` ends only the calling thread.
- Returning from `main` instead ends the whole process, while the process can remain alive after the main thread calls `pthread_exit` if other threads still run.
- Joinable threads retain resources until joined; detached threads release resources when they terminate and cannot be joined.
- The Linux trace distinguishes `exit`, which terminates a thread, from `exit_group`, which terminates all threads in a process.
39:10
Pthread Attributes and the Default Stack Size
- Pthread attributes can be initialized and used to set or query a thread’s stack size and detach state.
- The demonstrated Linux default thread stack size is 8 MB.
- Each stack has a guard page beneath it to help detect stack overflow.
40:50
Launching Four Threads and Passing IDs on the Heap
- The example creates four threads, assigns IDs 1 through 4, and has each print values 0 through 9.
- Each thread preserves its own counting order, but scheduling makes the order of output between threads unpredictable.
- The initial version allocates an integer on the heap for each thread’s argument, then the thread reads and frees that allocation.
46:50
Why Passing a Loop Variable’s Stack Address Breaks
- Passing `&id` from the thread-creating function gives workers a pointer to a stack variable that can be overwritten as the loop advances.
- The resulting output can contain repeated IDs, such as multiple threads reporting 3 or 4, because workers may read the value after the main thread updates it.
- Heap allocation provides storage that outlives the creator’s stack frame; the worker can safely read its assigned integer and free it when finished.
- The lecture closes by flagging race conditions as the next topic rather than developing their treatment here.
Summary, takeaways, and chapters were generated by AI from the video's transcript and may contain errors. The video belongs to its creator, Jon Eyolfson.