What Does an OS Do?
An operating system is the software layer between hardware and applications. It manages the CPU, memory, storage, and I/O devices — abstracting the hardware so programs don't have to deal with it directly. Core responsibilities: process management, memory management, file systems, and I/O.
Processes and Threads
A process is an independent program in execution — it has its own memory space (code, heap, stack), file handles, and CPU state. Threads are lightweight execution units within a process that share the same memory space but have their own stack and registers.
| Aspect | Process | Thread |
|---|---|---|
| Memory | Separate address space | Shared with other threads in same process |
| Creation cost | High (fork copies address space) | Low (shares most resources) |
| Communication | IPC: pipes, sockets, shared memory | Direct shared memory (needs synchronisation) |
| Isolation | Crash doesn't affect other processes | One thread crash can kill the whole process |
| Use case | Isolated services (microservices, web workers) | Parallel tasks within an app (server requests) |
Process States
A process moves through states during its life. The OS scheduler decides which ready process runs next.
New → Ready → Running → Terminated
↑ ↓ ↑
Wait ← I/O event / sleep
(Waiting/Blocked)
- New — being created
- Ready — in the run queue, waiting for CPU
- Running — executing on CPU right now
- Waiting/Blocked — waiting for I/O or an event (not using CPU)
- Terminated — finished or killed
CPU Scheduling
The scheduler decides which ready process gets the CPU next. The goal is to maximise CPU utilisation and throughput while minimising turnaround time and response time.
| Algorithm | How it works | Problem |
|---|---|---|
| FCFS | First Come First Served — run in arrival order, non-preemptive | Convoy effect — one slow process blocks everything |
| SJF | Shortest Job First — run shortest burst time next | Can't know burst time in advance; starvation of long jobs |
| Round Robin | Each process gets a fixed time quantum; preemptive | High context-switch overhead if quantum too small |
| Priority | Higher-priority process runs first | Starvation — low-priority processes may never run (fix: aging) |
| MLFQ | Multi-Level Feedback Queue — adjusts priority based on behaviour | Complex to tune; most real OS schedulers are based on this |
Memory Management
Each process thinks it has exclusive access to a large, contiguous address space — this is virtual memory. The OS translates virtual addresses to physical RAM addresses using a page table.
Paging
Memory is divided into fixed-size pages (virtual) and frames (physical), typically 4KB. The page table maps page numbers to frame numbers. When a process accesses a page not in RAM, a page fault occurs — the OS loads the page from disk.
TLB — Translation Lookaside Buffer
Looking up the page table on every memory access would be slow (it's in RAM). The TLB is a small hardware cache that stores recent virtual→physical translations, making most address translations O(1) instead of requiring a RAM lookup.
Page Replacement Algorithms
| Algorithm | Evicts | Notes |
|---|---|---|
| FIFO | Oldest loaded page | Simple; Bélády's anomaly — more frames can cause more faults |
| LRU | Least Recently Used | Good in practice; expensive to implement exactly |
| Optimal | Page used furthest in the future | Theoretical best; impossible in practice (need to know future) |
| Clock (LRU approx) | Page with reference bit = 0 | Used in real OS; efficient approximation of LRU |
Synchronisation — Race Conditions & Locks
When two threads share memory, they can create a race condition — the result depends on execution order. The classic example: two threads both read, increment, and write a counter. Without synchronisation, increments are lost.
Solutions: mutex (mutual exclusion lock) — only one thread holds the lock at a time; semaphore — allows N threads to enter a critical section; monitor — a higher-level abstraction combining a mutex with a condition variable.
// Concept (pseudocode)
mutex.lock()
// critical section — only one thread here at a time
counter++
mutex.unlock()
// Semaphore — limits concurrent access (e.g., connection pool of 10)
semaphore = Semaphore(10)
semaphore.wait() // decrement; block if 0
// use connection
semaphore.signal() // increment; wake a waiting thread
Deadlocks
A deadlock occurs when two or more processes are each waiting for a resource held by the other, forming a cycle — and none can proceed. All four conditions must hold simultaneously for a deadlock to occur.
| Condition | Meaning |
|---|---|
| Mutual Exclusion | At least one resource is non-shareable (only one process at a time) |
| Hold and Wait | A process holds at least one resource while waiting for more |
| No Preemption | Resources can't be forcibly taken; processes release voluntarily |
| Circular Wait | A cycle: P1 waits for P2's resource, P2 waits for P1's resource |
Prevention: break one condition — e.g., require processes to request all resources at once (eliminates Hold and Wait), or impose a total ordering on resource acquisition (eliminates Circular Wait).
Detection and recovery: let deadlocks happen, detect them using a resource allocation graph, then resolve by killing a process or preempting a resource.
File Systems
A file system organises data on storage devices into a hierarchy of files and directories. The OS provides a uniform interface regardless of whether storage is SSD, HDD, or network-attached.
Unix file systems use inodes — data structures that store file metadata (permissions, size, timestamps, data block pointers) but not the filename. The filename-to-inode mapping is stored in the directory. This design allows hard links (multiple filenames pointing to the same inode).
| Concept | Description |
|---|---|
| inode | File metadata + pointers to data blocks; identified by inode number |
| Hard link | Another directory entry pointing to the same inode (shared data) |
| Soft link (symlink) | A file containing the path to another file (breaks if target deleted) |
| Journaling | Log writes before executing; recover to consistent state after crash (ext4, NTFS) |
Key Takeaways
- A process is isolated (own memory); a thread shares memory with siblings — concurrency is powerful but requires synchronisation.
- Round Robin with a good time quantum is the most common scheduling basis in real OS kernels.
- Virtual memory allows programs to use more memory than physically available via paging and demand loading.
- Deadlock requires all four conditions; break any one to prevent it. Consistent lock ordering is the most practical fix.
- LRU is the de-facto page replacement choice; real OS use the Clock algorithm as an efficient approximation.