1.4 Threads, Concurrency, and Parallelism
Prerequisites: Processes and Memory
Estimated time: 8–12 minutes
You are ready to continue when: you can distinguish threads, concurrency, and parallelism, and explain the role of the scheduler in this distinction.
Three tasks have started: one waits for the network, one parses a file, and one computes a result. Their lifetimes can overlap even when only one occupies a particular logical CPU at a given instant.
Several tasks can be in progress without executing at the same instant. Concurrency describes overlapping progress; parallelism describes simultaneous execution.
Threads Are the Scheduler's Basic Unit
A normally running user process typically has at least one thread. Threads are the basic unit on which the modern operating system scheduler arranges execution; threads within the same process share address space and most of the resources of a process. This sharing makes communication cheaper, and also means that a single error in one thread could damage data that another thread is using.
- Concurrency: Multiple tasks have overlapping lifecycles and can be interleaved on a single logical CPU.
- Parallelism: Multiple execution resources advance different tasks at the same time.
Concurrency is suitable for organizing waits for I/O, handling multiple requests, or splitting independent work; parallelism uses multiple logical CPUs to compute simultaneously. Both can coexist.
The Boundaries of the Scheduler Model
Introductory materials often say, "Each core does one thing at a time, and the system switches once every 30 milliseconds." The reality is more complex:
- The scheduler assigns runnable threads to logical CPUs;
- Threads can be paused due to I/O, locks, sleep, priority, or preemption;
- The scheduling interval is determined by the kernel, load, and policy, and is not uniformly 30 ms;
- Pipelining, out-of-order execution, vector units, and SMT make "one instruction per core" only an approximation.
For this chapter, just remember: processes provide resource boundaries, threads execute work, and the scheduler decides when and on which logical CPU a runnable thread should proceed.
Observing Thread Snapshots
ps -eLo pid,tid,psr,stat,%cpu,comm | head -20Type: runnableEnvironment: Linux procps psObservation: PID is the process ID, TID is the thread ID, and PSR is the logical CPU on which the thread last executed. A single snapshot cannot prove that a thread has been fixed on that CPU.
On macOS, you can use Activity Monitor to view the number of threads, or use the native ps help to choose the appropriate field. On Windows PowerShell, you can run Get-Process | Select-Object -First 10 Name,Id,Threads, where Threads is a collection of thread objects, not CPU parallelism.
Two Common Misconceptions
Running many processes means all processes are using the CPU at the same time. Many processes are waiting for input, network, locks, or timers, and may not be runnable at the time of sampling.
A single browser tab equals a single process. Browsers split or reuse processes based on sites, renderers, extensions, GPUs, and security policies. The model varies with version and configuration.
Wrapping Up with a Single Observation
Find a multi-threaded application, record its process ID and thread count, and then explain why this snapshot cannot prove that all threads are running in parallel. Also give an example of several tasks taking turns on one logical CPU.
The next page's Exploring the System Experiment will tie together all the observations from this chapter.