Operating Systems Cheatsheet
Threads
Use this Operating Systems reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
Thread Fundamentals
A thread (thread of execution) is the smallest unit the OS scheduler manages. Multiple threads share the same process address space but each has its own stack, registers, and program counter.
Process = resource container. Thread = execution stream within that container.
Process vs Thread
| Aspect | Process | Thread |
|---|---|---|
| Address space | Separate | Shared with siblings |
| Creation cost | High (fork + copy) | Low (stack + TCB only) |
| Context switch cost | High (TLB flush, etc.) | Lower (same page table) |
| Communication | IPC (pipe, socket, …) | Direct shared memory |
| Fault isolation | Strong | Weak (crash kills all) |
| Typical creation time | ~1 ms | ~10 µs |
Thread Models
User-Level Threads (N:1)
N user threads → 1 kernel thread. Thread library manages scheduling in user space.
- Pros: fast switch (no syscall), portable
- Cons: one blocking syscall blocks entire process; no true parallelism
Kernel-Level Threads (1:1)
Each user thread maps to one kernel thread.
Used by Linux (clone()), Windows.
- Pros: true parallelism on multicore; blocking call only blocks that thread
- Cons: thread creation/switch requires syscall overhead
Hybrid (M:N)
M user threads mapped to N kernel threads (N ≤ M). Solaris originally; Go runtime goroutines approximate this.
| Model | Parallelism | Creation cost | Blocking I/O |
|---|---|---|---|
| N:1 (user) | No | Very low | Blocks all |
| 1:1 (kernel) | Yes | Medium | Fine |
| M:N (hybrid) | Yes | Low | Fine |
POSIX Threads (pthreads) Quick Reference
#include <pthread.h> void *worker(void *arg) { int n = *(int *)arg; return (void *)(long)(n * 2); } int main() { pthread_t tid; int val = 5; pthread_create(&tid, NULL, worker, &val); // create void *ret; pthread_join(tid, &ret); // wait + collect return // ret == 10 }
| Function | Purpose |
|---|---|
pthread_create(tid, attr, fn, arg) | Spawn new thread |
pthread_join(tid, retval) | Wait for thread to finish |
pthread_detach(tid) | Auto-cleanup on exit (no join) |
pthread_exit(val) | Terminate calling thread |
pthread_self() | Get own TID |
pthread_cancel(tid) | Request cancellation |
pthread_mutex_lock/unlock | Mutual exclusion |
pthread_cond_wait/signal | Condition variables |
Thread Safety and Race Conditions
A function is thread-safe if it works correctly when called simultaneously by multiple threads.
// NOT thread-safe — race on global counter int counter = 0; void increment() { counter++; } // read-modify-write is non-atomic // Thread-safe with mutex pthread_mutex_t mu = PTHREAD_MUTEX_INITIALIZER; void increment_safe() { pthread_mutex_lock(&mu); counter++; pthread_mutex_unlock(&mu); }
Thread-safe strategies:
- Use mutexes / locks around shared state
- Use thread-local storage (__thread / pthread_key_t)
- Use atomic operations (<stdatomic.h>, std::atomic<>)
- Make functions reentrant (use only local variables + immutable globals)
Thread Lifecycle
Created ──→ Runnable ←──── Blocked
│ event ↑
scheduled│ │wait
↓ │
Running ─────────┘
│
pthread_exit / return
↓
Terminated
(zombie until joined or detached)Thread Pools
Pre-allocate N threads; submit tasks to a work queue instead of spawning per-task.
Producer ──→ [Task Queue] ──→ Worker 1 ──→ Worker 2 ──→ Worker N
Benefits: eliminates spawn/teardown overhead; bounds concurrency; reuses warm caches.
Implementations: Java ExecutorService, Python concurrent.futures.ThreadPoolExecutor, C pthreads + queue.
CPU Affinity
Bind a thread to specific CPU cores to reduce cache misses from migration.
cpu_set_t set; CPU_ZERO(&set); CPU_SET(2, &set); // pin to core 2 sched_setaffinity(0, sizeof(set), &set);
Useful for real-time threads and NUMA-aware high-performance code.
Common Threading Bugs
| Bug | Description | Prevention |
|---|---|---|
| Race condition | Output depends on interleaving order | Locks, atomics |
| Deadlock | Threads wait on each other's locks forever | Lock ordering |
| Livelock | Threads keep responding but make no progress | Backoff/randomize |
| Starvation | Thread never gets CPU or lock | Fair scheduling, priority |
| False sharing | Different threads write to same cache line | Pad structs to cache-line size |
| Priority inversion | Low-priority thread holds lock needed by high-priority | Priority inheritance |