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.

What Threads Share vs Own

ResourceShared (all threads in process)Per-Thread (private)
Code (text segment)
Data segment + heap
Open file descriptors
Signal handlers
Working directory
PID / PPID
Stack
CPU registers
Program counter
Thread ID (TID)
Signal mask
errno✓ (thread-local)

Process vs Thread

AspectProcessThread
Address spaceSeparateShared with siblings
Creation costHigh (fork + copy)Low (stack + TCB only)
Context switch costHigh (TLB flush, etc.)Lower (same page table)
CommunicationIPC (pipe, socket, …)Direct shared memory
Fault isolationStrongWeak (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.

ModelParallelismCreation costBlocking I/O
N:1 (user)NoVery lowBlocks all
1:1 (kernel)YesMediumFine
M:N (hybrid)YesLowFine

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
}
FunctionPurpose
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/unlockMutual exclusion
pthread_cond_wait/signalCondition 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 / returnTerminated
           (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

BugDescriptionPrevention
Race conditionOutput depends on interleaving orderLocks, atomics
DeadlockThreads wait on each other's locks foreverLock ordering
LivelockThreads keep responding but make no progressBackoff/randomize
StarvationThread never gets CPU or lockFair scheduling, priority
False sharingDifferent threads write to same cache linePad structs to cache-line size
Priority inversionLow-priority thread holds lock needed by high-priorityPriority inheritance