02. Operating Systems - Ultimate Master Textbook & Worked Examples Reference
Module Focus: Comprehensive Theory + Step-by-Step Worked Numerical Examples under Every Pillar across All 5 Core Operating Systems Topics.
🏛️ Pillar 1: Process Management & CPU Scheduling
1.1 Process Architecture & Address Space Layout
A Process is a program in execution with an isolated virtual address space provided by the Operating System.
VIRTUAL ADDRESS SPACE LAYOUT
+------------------------------------+ High Memory Address (0x7FFFFFFF...)
| Stack (Local Vars, Function Frames)| v (Grows Downward)
| |
| Heap (Dynamic Memory: malloc/new) | ^ (Grows Upward)
+------------------------------------+
| Data Segment (Globals, Statics) |
+------------------------------------+
| Text Segment (Machine Instructions)| Low Memory Address (0x00000000...)
+------------------------------------+
Process State Transitions:
+-------------------------------------------------+
| |
v |
[New] -> [Ready] <--- (Time Quantum Expired / Preempted) --+
| |
| (Scheduled by CPU Scheduler) |
v |
[Running] ------------------------------------------+
|
+---> (I/O Request / Wait for Event) ---> [Waiting/Blocked]
| |
| |
v v
[Terminated] <------- (I/O Completed) --------------+
1.2 Performance Metrics & Core Equations
- Completion Time ($CT$): Timestamp at which a process finishes execution.
- Turnaround Time ($TAT$): Total time elapsed from arrival to completion. $$TAT = CT - AT$$
- Waiting Time ($WT$): Total time spent sitting in the Ready Queue. $$WT = TAT - BT$$
- Response Time ($RT$): Time from arrival until the process is first assigned CPU execution. $$RT = \text{First Run Timestamp} - AT$$
- CPU Utilization: $\frac{\text{Total CPU Busy Time}}{\text{Total Elapsed Time}} \times 100\%$
- Throughput: $\frac{\text{Total Processes Completed}}{\text{Total Unit Time}}$
1.3 Worked Numerical Examples for ALL 8 CPU Scheduling Algorithms
Master Benchmark Dataset (for Algorithms 1–6):
| Process | Arrival Time ($AT$) | Burst Time ($BT$) | Priority (Lower Int = Higher Priority) |
|---|---|---|---|
| $P_1$ | 0 ms | 8 ms | 3 |
| $P_2$ | 1 ms | 4 ms | 1 (Highest) |
| $P_3$ | 2 ms | 9 ms | 4 |
| $P_4$ | 3 ms | 5 ms | 2 |
1. FCFS (First-Come, First-Served)
- Nature: Non-preemptive. Executes processes strictly in order of arrival.
✏️ Worked Numerical Step-by-Step Trace:
- $t=0$: $P_1$ arrives $\implies$ runs $t=0 \to 8$. ($CT = 8$)
- $t=8$: $P_2$ runs $t=8 \to 12$. ($CT = 12$)
- $t=12$: $P_3$ runs $t=12 \to 21$. ($CT = 21$)
- $t=21$: $P_4$ runs $t=21 \to 26$. ($CT = 26$)
Gantt Chart:
| P1 (0 - 8) | P2 (8 - 12) | P3 (12 - 21) | P4 (21 - 26) |
📊 Computation Table:
| Process | $AT$ | $BT$ | $CT$ | $TAT = CT - AT$ | $WT = TAT - BT$ | $RT$ |
|---|---|---|---|---|---|---|
| $P_1$ | 0 | 8 | 8 | $8 - 0 = 8$ | $8 - 8 = 0$ | $0 - 0 = 0$ |
| $P_2$ | 1 | 4 | 12 | $12 - 1 = 11$ | $11 - 4 = 7$ | $8 - 1 = 7$ |
| $P_3$ | 2 | 9 | 21 | $21 - 2 = 19$ | $19 - 9 = 10$ | $12 - 2 = 10$ |
| $P_4$ | 3 | 5 | 26 | $26 - 3 = 23$ | $23 - 5 = 18$ | $21 - 3 = 18$ |
- Average Turnaround Time: $\frac{8 + 11 + 19 + 23}{4} = \mathbf{15.25 \text{ ms}}$
- Average Waiting Time: $\frac{0 + 7 + 10 + 18}{4} = \mathbf{8.75 \text{ ms}}$
2. SJF (Shortest Job First - Non-Preemptive)
- Nature: Non-preemptive. Selects process with smallest total burst time among ready processes.
✏️ Worked Numerical Step-by-Step Trace:
- $t=0$: Only $P_1$ is ready. $P_1$ runs $t=0 \to 8$. ($CT=8$).
- $t=8$: $P_2(BT=4), P_3(BT=9), P_4(BT=5)$ are all in Ready Queue.
- Smallest $BT$ is $P_2(4) \implies$ runs $t=8 \to 12$. ($CT=12$).
- $t=12$: Ready: $P_4(5), P_3(9)$.
- Smallest $BT$ is $P_4(5) \implies$ runs $t=12 \to 17$. ($CT=17$).
- $t=17$: Ready: $P_3(9) \implies$ runs $t=17 \to 26$. ($CT=26$).
Gantt Chart:
| P1 (0 - 8) | P2 (8 - 12) | P4 (12 - 17) | P3 (17 - 26) |
📊 Computation Table:
| Process | $AT$ | $BT$ | $CT$ | $TAT$ | $WT$ | $RT$ |
|---|---|---|---|---|---|---|
| $P_1$ | 0 | 8 | 8 | 8 | 0 | 0 |
| $P_2$ | 1 | 4 | 12 | 11 | 7 | 7 |
| $P_3$ | 2 | 9 | 26 | 24 | 15 | 15 |
| $P_4$ | 3 | 5 | 17 | 14 | 9 | 9 |
- Average Turnaround Time: $\frac{8 + 11 + 24 + 14}{4} = \mathbf{14.25 \text{ ms}}$
- Average Waiting Time: $\frac{0 + 7 + 15 + 9}{4} = \mathbf{7.75 \text{ ms}}$
3. SRTF (Shortest Remaining Time First - Preemptive SJF)
- Nature: Preemptive. Preempts current process if a new process arrives with smaller remaining burst time.
✏️ Worked Numerical Step-by-Step Trace:
- $t=0$: Run $P_1$. Remaining $BT(P_1) = 8$.
- $t=1$: $P_2(BT=4)$ arrives. Remaining $BT(P_1) = 7$. Since $4 < 7$, preempt $P_1$. Run $P_2$.
- $t=2$: $P_3(BT=9)$ arrives. $BT(P_2)$ remaining $= 3$. Continue $P_2$.
- $t=3$: $P_4(BT=5)$ arrives. $BT(P_2)$ remaining $= 2$. Continue $P_2$.
- $t=5$: $P_2$ completes ($CT=5$). Ready: $P_4(5), P_1(7), P_3(9)$. Run $P_4$.
- $t=10$: $P_4$ completes ($CT=10$). Ready: $P_1(7), P_3(9)$. Run $P_1$.
- $t=17$: $P_1$ completes ($CT=17$). Ready: $P_3(9)$. Run $P_3$.
- $t=26$: $P_3$ completes ($CT=26$).
Gantt Chart:
| P1 (0-1) | P2 (1-5) | P4 (5-10) | P1 (10-17) | P3 (17-26) |
📊 Computation Table:
| Process | $AT$ | $BT$ | $CT$ | $TAT$ | $WT$ | $RT$ |
|---|---|---|---|---|---|---|
| $P_1$ | 0 | 8 | 17 | 17 | $17 - 8 = 9$ | $0 - 0 = 0$ |
| $P_2$ | 1 | 4 | 5 | 4 | $4 - 4 = 0$ | $1 - 1 = 0$ |
| $P_3$ | 2 | 9 | 26 | 24 | $24 - 9 = 15$ | $17 - 2 = 15$ |
| $P_4$ | 3 | 5 | 10 | 7 | $7 - 5 = 2$ | $5 - 3 = 2$ |
- Average Turnaround Time: $\frac{17 + 4 + 24 + 7}{4} = \mathbf{13.0 \text{ ms}}$
- Average Waiting Time: $\frac{9 + 0 + 15 + 2}{4} = \mathbf{6.5 \text{ ms}}$
4. Non-Preemptive Priority Scheduling
- Nature: Non-preemptive. Selects process with highest priority (lowest integer value).
✏️ Worked Numerical Step-by-Step Trace:
- $t=0$: Only $P_1$ is ready ($\text{Pri}=3$). Runs $t=0 \to 8$. ($CT=8$).
- $t=8$: Ready: $P_2(\text{Pri}=1), P_4(\text{Pri}=2), P_3(\text{Pri}=4)$.
- Highest priority is $P_2 \implies$ runs $t=8 \to 12$. ($CT=12$).
- $t=12$: Ready: $P_4(\text{Pri}=2), P_3(\text{Pri}=4) \implies P_4$ runs $t=12 \to 17$. ($CT=17$).
- $t=17$: $P_3(\text{Pri}=4)$ runs $t=17 \to 26$. ($CT=26$).
Gantt Chart:
| P1 (0 - 8) | P2 (8 - 12) | P4 (12 - 17) | P3 (17 - 26) |
📊 Computation Table:
| Process | $AT$ | $BT$ | Priority | $CT$ | $TAT$ | $WT$ | $RT$ |
|---|---|---|---|---|---|---|---|
| $P_1$ | 0 | 8 | 3 | 8 | 8 | 0 | 0 |
| $P_2$ | 1 | 4 | 1 | 12 | 11 | 7 | 7 |
| $P_3$ | 2 | 9 | 4 | 26 | 24 | 15 | 15 |
| $P_4$ | 3 | 5 | 2 | 17 | 14 | 9 | 9 |
- Average Turnaround Time: $\mathbf{14.25 \text{ ms}}$
- Average Waiting Time: $\mathbf{7.75 \text{ ms}}$
5. Preemptive Priority Scheduling
- Nature: Preemptive. Preempts running process if a process with strictly higher priority arrives.
✏️ Worked Numerical Step-by-Step Trace:
- $t=0$: Run $P_1(\text{Pri}=3)$.
- $t=1$: $P_2(\text{Pri}=1)$ arrives. Priority $1 < 3 \implies$ Preempt $P_1$. Run $P_2$.
- $t=2$: $P_3(\text{Pri}=4)$ arrives. $P_2(\text{Pri}=1)$ higher priority. Continue $P_2$.
- $t=3$: $P_4(\text{Pri}=2)$ arrives. $P_2(\text{Pri}=1)$ higher priority. Continue $P_2$.
- $t=5$: $P_2$ finishes ($CT=5$). Ready: $P_4(2), P_1(3), P_3(4)$. Highest is $P_4 \implies$ run $P_4$.
- $t=10$: $P_4$ finishes ($CT=10$). Ready: $P_1(3), P_3(4) \implies$ run $P_1$.
- $t=17$: $P_1$ finishes ($CT=17$). Ready: $P_3(4) \implies$ run $P_3$.
- $t=26$: $P_3$ finishes ($CT=26$).
Gantt Chart:
| P1 (0-1) | P2 (1-5) | P4 (5-10) | P1 (10-17) | P3 (17-26) |
📊 Computation Table:
| Process | $AT$ | $BT$ | Priority | $CT$ | $TAT$ | $WT$ | $RT$ |
|---|---|---|---|---|---|---|---|
| $P_1$ | 0 | 8 | 3 | 17 | 17 | 9 | 0 |
| $P_2$ | 1 | 4 | 1 | 5 | 4 | 0 | 0 |
| $P_3$ | 2 | 9 | 4 | 26 | 24 | 15 | 15 |
| $P_4$ | 3 | 5 | 2 | 10 | 7 | 2 | 2 |
- Average Turnaround Time: $\mathbf{13.0 \text{ ms}}$
- Average Waiting Time: $\mathbf{6.5 \text{ ms}}$
6. Round Robin (RR) Scheduling ($Time\ Quantum\ q = 4\text{ ms}$)
- Nature: Preemptive circular queue scheduling.
✏️ Worked Numerical Step-by-Step Trace & Ready Queue Tracking:
- $t=0$: Ready Queue: $[P_1]$. Run $P_1$ for $q=4\text{ms}$ ($t=0 \to 4$).
- During $t=1$: $P_2$ arrives.
- During $t=2$: $P_3$ arrives.
- During $t=3$: $P_4$ arrives.
- $t=4$: $P_1$ quantum expires (rem $BT=4$). Re-queued behind arrived processes.
- Ready Queue: $[P_2, P_3, P_4, P_1]$. Run $P_2(BT=4)$ for $t=4 \to 8$.
- $t=8$: $P_2$ finishes ($CT=8$). Ready Queue: $[P_3, P_4, P_1]$. Run $P_3(BT=9)$ for $q=4\text{ms}$ ($t=8 \to 12$).
- $t=12$: $P_3$ quantum expires (rem $BT=5$). Ready Queue: $[P_4, P_1, P_3]$. Run $P_4(BT=5)$ for $q=4\text{ms}$ ($t=12 \to 16$).
- $t=16$: $P_4$ quantum expires (rem $BT=1$). Ready Queue: $[P_1, P_3, P_4]$. Run $P_1(rem\ BT=4)$ for $t=16 \to 20$.
- $t=20$: $P_1$ finishes ($CT=20$). Ready Queue: $[P_3, P_4]$. Run $P_3(rem\ BT=5)$ for $q=4\text{ms}$ ($t=20 \to 24$).
- $t=24$: $P_3$ quantum expires (rem $BT=1$). Ready Queue: $[P_4, P_3]$. Run $P_4(rem\ BT=1)$ for $t=24 \to 25$.
- $t=25$: $P_4$ finishes ($CT=25$). Ready Queue: $[P_3]$. Run $P_3(rem\ BT=1)$ for $t=25 \to 26$.
- $t=26$: $P_3$ finishes ($CT=26$).
Gantt Chart:
| P1 (0-4) | P2 (4-8) | P3 (8-12) | P4 (12-16) | P1 (16-20) | P3 (20-24) | P4 (24-25) | P3 (25-26) |
📊 Computation Table:
| Process | $AT$ | $BT$ | $CT$ | $TAT = CT - AT$ | $WT = TAT - BT$ | $RT$ |
|---|---|---|---|---|---|---|
| $P_1$ | 0 | 8 | 20 | $20 - 0 = 20$ | $20 - 8 = 12$ | $0 - 0 = 0$ |
| $P_2$ | 1 | 4 | 8 | $8 - 1 = 7$ | $7 - 4 = 3$ | $4 - 1 = 3$ |
| $P_3$ | 2 | 9 | 26 | $26 - 2 = 24$ | $24 - 9 = 15$ | $8 - 2 = 6$ |
| $P_4$ | 3 | 5 | 25 | $25 - 3 = 22$ | $22 - 5 = 17$ | $12 - 3 = 9$ |
- Average Turnaround Time: $\frac{20 + 7 + 24 + 22}{4} = \mathbf{18.25 \text{ ms}}$
- Average Waiting Time: $\frac{12 + 3 + 15 + 17}{4} = \mathbf{11.75 \text{ ms}}$
7. Multilevel Queue Scheduling
- Nature: Memory divided into static queues based on process type (System vs User). Fixed priority preemption between queues.
✏️ Worked Numerical Step-by-Step Trace:
- Queue 1 (System Processes - Priority 1, High): RR ($q=2\text{ms}$). Processes: $P_{sys1} (BT=3, AT=0)$, $P_{sys2} (BT=2, AT=0)$.
-
Queue 2 (User Processes - Priority 2, Low): FCFS. Processes: $P_{user1} (BT=4, AT=0)$.
-
Queue 1 runs first (Absolute Priority):
- $t=0 \to 2$: $P_{sys1}$ runs. (Rem $BT = 1$).
- $t=2 \to 4$: $P_{sys2}$ runs. ($P_{sys2}$ completes, $CT=4$).
- $t=4 \to 5$: $P_{sys1}$ runs. ($P_{sys1}$ completes, $CT=5$).
- Queue 1 is now empty. CPU switches to Queue 2:
- $t=5 \to 9$: $P_{user1}$ runs FCFS. ($P_{user1}$ completes, $CT=9$).
Gantt Chart:
| Psys1 (0-2) | Psys2 (2-4) | Psys1 (4-5) | Puser1 (5-9) |
📊 Computation Table:
| Process | Queue | $AT$ | $BT$ | $CT$ | $TAT$ | $WT$ |
|---|---|---|---|---|---|---|
| $P_{sys1}$ | System ($Q_1$) | 0 | 3 | 5 | 5 | $5 - 3 = 2$ |
| $P_{sys2}$ | System ($Q_1$) | 0 | 2 | 4 | 4 | $4 - 2 = 2$ |
| $P_{user1}$ | User ($Q_2$) | 0 | 4 | 9 | 9 | $9 - 4 = 5$ |
8. Multilevel Feedback Queue (MLFQ) Scheduling
- Nature: Dynamic movement between queues based on CPU burst execution duration (Demotes CPU-bound processes, promotes aging processes).
✏️ Worked Numerical Step-by-Step Trace:
- Queue 0 ($Q_0$): Round Robin ($q = 8\text{ ms}$)
- Queue 1 ($Q_1$): Round Robin ($q = 16\text{ ms}$)
- Queue 2 ($Q_2$): FCFS
Process Execution Trace: Process $P_1$ with $BT = 35\text{ ms}$ arrives at $t=0$: 1. Enters $Q_0$: Runs for $8\text{ms}$ slice ($t=0 \to 8$). Remaining $BT = 27\text{ms}$. - Did not finish within $q=8\text{ms} \implies$ Demoted to $Q_1$. 2. Enters $Q_1$: Runs for $16\text{ms}$ slice ($t=8 \to 24$). Remaining $BT = 11\text{ms}$. - Did not finish within $q=16\text{ms} \implies$ Demoted to $Q_2$. 3. Enters $Q_2$: Runs under FCFS for remaining $11\text{ms}$ ($t=24 \to 35$). - Finishes execution at $t=35\text{ms}$! ($CT=35$, $TAT=35$, $WT=0$).
🏛️ Pillar 2: Memory Management & ALL 7 Page Replacement Algorithms Masterclass
2.1 Paging & Address Translation Math
Structure of Virtual and Physical Addresses:
- Logical Address: Consists of Page Number ($p$) and Page Offset ($d$).
- Physical Address: Consists of Frame Number ($f$) and Frame Offset ($d$).
- Key Equations: $$\text{Page Size} = 2^d \text{ bytes}$$ $$\text{Number of Pages} = 2^p = \frac{\text{Logical Address Space}}{\text{Page Size}}$$ $$\text{Page Table Size} = \text{Number of Pages} \times \text{Page Table Entry Size}$$
✏️ Worked Numerical Example 1 (Logical Address Translation):
Given a 32-bit Logical Address Space with a Page Size of $4 \text{ KB} = 4096 \text{ bytes} = 2^{12} \text{ bytes}$. Page Table Entry size $= 4 \text{ bytes}$. Given Logical Address $= \text{0x00003024} = 12324_{10}$. Page Table Mapping: Page $3 \to$ Frame $7$.
- Calculate Bit Split:
- Offset bits $d = 12$ bits (since $2^{12} = 4096$).
- Page Number bits $p = 32 - 12 = 20$ bits.
- Extract Page Number ($p$) and Offset ($d$):
- $p = \lfloor 12324 / 4096 \rfloor = \mathbf{3}$
- $d = 12324 \pmod{4096} = \mathbf{36} = \mathbf{0x024}$
- Calculate Physical Address:
- Frame Number $f = 7$.
- $\text{Physical Address} = (f \times \text{Page Size}) + d = (7 \times 4096) + 36 = 28672 + 36 = \mathbf{28708_{10}} = \mathbf{0x00007024}$.
✏️ Worked Numerical Example 2 (TLB Effective Access Time):
- TLB Hit Ratio ($h$): $90\% = 0.90$
- TLB Access Time ($t_{\text{tlb}}$): $20 \text{ ns}$
- Main Memory Access Time ($t_{\text{mem}}$): $100 \text{ ns}$
$$\text{Effective Access Time (EAT)} = h \cdot (t_{\text{tlb}} + t_{\text{mem}}) + (1 - h) \cdot (t_{\text{tlb}} + 2 t_{\text{mem}})$$ $$\text{EAT} = 0.90 \cdot (20 + 100) + 0.10 \cdot (20 + 200) = 0.90(120) + 0.10(220) = 108 + 22 = \mathbf{130 \text{ ns}}$$
2.2 Complete Breakdown & Trace Benchmark for ALL 7 Page Replacement Algorithms
Master Benchmark Setup:
- Reference String: 7, 0, 1, 2, 0, 3, 0, 4, 2, 3
- Frame Capacity: 3 Frames (Initially empty: [-, -, -]).
1. FIFO (First-In, First-Out)
- Policy: Replaces the oldest page in memory.
- Defect: Suffers from Belady's Anomaly (increasing frame allocation can increase page fault rate).
✏️ Step-by-Step Execution Trace:
| Step | Ref Page | Frame 0 | Frame 1 | Frame 2 | Status | Evicted Page |
|---|---|---|---|---|---|---|
| 1 | 7 |
7 | - | - | FAULT | None |
| 2 | 0 |
7 | 0 | - | FAULT | None |
| 3 | 1 |
7 | 0 | 1 | FAULT | None |
| 4 | 2 |
2 | 0 | 1 | FAULT | 7 |
| 5 | 0 |
2 | 0 | 1 | HIT | None |
| 6 | 3 |
2 | 3 | 1 | FAULT | 0 |
| 7 | 0 |
2 | 3 | 0 | FAULT | 1 |
| 8 | 4 |
4 | 3 | 0 | FAULT | 2 |
| 9 | 2 |
4 | 2 | 0 | FAULT | 3 |
| 10 | 3 |
4 | 2 | 3 | FAULT | 0 |
- Total FIFO Faults: $\mathbf{9 \text{ Page Faults}}$
💡 Belady's Anomaly Numerical Proof:
For Reference String 1, 2, 3, 4, 1, 2, 5, 1, 2, 3, 4, 5:
- With 3 Frames $\implies \mathbf{9 \text{ Page Faults}}$.
- With 4 Frames $\implies \mathbf{10 \text{ Page Faults}}$ (Faults increase despite adding memory!).
2. LRU (Least Recently Used)
- Policy: Replaces the page that has not been used for the longest period in the past.
- Property: Stack Algorithm (Immune to Belady's Anomaly).
✏️ Step-by-Step Execution Trace:
| Step | Ref Page | Frame 0 | Frame 1 | Frame 2 | Status | Recency Order (Oldest $\to$ Newest) |
|---|---|---|---|---|---|---|
| 1 | 7 |
7 | - | - | FAULT | [7] |
| 2 | 0 |
7 | 0 | - | FAULT | [7, 0] |
| 3 | 1 |
7 | 0 | 1 | FAULT | [7, 0, 1] |
| 4 | 2 |
2 | 0 | 1 | FAULT | [0, 1, 2] (Evict 7) |
| 5 | 0 |
2 | 0 | 1 | HIT | [1, 2, 0] |
| 6 | 3 |
2 | 0 | 3 | FAULT | [2, 0, 3] (Evict 1) |
| 7 | 0 |
2 | 0 | 3 | HIT | [2, 3, 0] |
| 8 | 4 |
4 | 0 | 3 | FAULT | [3, 0, 4] (Evict 2) |
| 9 | 2 |
4 | 0 | 2 | FAULT | [0, 4, 2] (Evict 3) |
| 10 | 3 |
4 | 3 | 2 | FAULT | [4, 2, 3] (Evict 0) |
- Total LRU Faults: $\mathbf{8 \text{ Page Faults}}$
3. Optimal Page Replacement (OPT / MIN)
- Policy: Replaces the page that will not be used for the longest period of time in the future.
✏️ Step-by-Step Execution Trace:
| Step | Ref Page | Frame 0 | Frame 1 | Frame 2 | Status | Future Next Access |
|---|---|---|---|---|---|---|
| 1 | 7 |
7 | - | - | FAULT | Never |
| 2 | 0 |
7 | 0 | - | FAULT | Step 5 |
| 3 | 1 |
7 | 0 | 1 | FAULT | Never |
| 4 | 2 |
2 | 0 | 1 | FAULT | Evict 7 (Never used again) |
| 5 | 0 |
2 | 0 | 1 | HIT | Step 7 |
| 6 | 3 |
2 | 0 | 3 | FAULT | Evict 1 (Never used again) |
| 7 | 0 |
2 | 0 | 3 | HIT | None |
| 8 | 4 |
4 | 0 | 3 | FAULT | Evict 2 (Used at Step 9 vs 3 at Step 10) |
| 9 | 2 |
4 | 0 | 2 | FAULT | Evict 3 |
| 10 | 3 |
4 | 0 | 3 | FAULT | Evict 2 |
- Total OPT Faults: $\mathbf{7 \text{ Page Faults}}$ (Theoretical Benchmark Minimum)
4. Second Chance (Clock Algorithm)
- Policy: Circular queue with a reference bit $R$.
- Access $\implies R = 1$.
- Replacement $\implies$ Check clock pointer: If $R=1 \implies$ reset $R=0$ and advance pointer. If $R=0 \implies$ replace page.
✏️ Step-by-Step Execution Trace:
| Step | Ref Page | Frame Array [F0, F1, F2] |
Ref Bits [R0, R1, R2] |
Clock Pointer | Status | Evicted Page |
|---|---|---|---|---|---|---|
| 1 | 7 |
[7, -, -] |
[1, 0, 0] |
1 | FAULT | None |
| 2 | 0 |
[7, 0, -] |
[1, 1, 0] |
2 | FAULT | None |
| 3 | 1 |
[7, 0, 1] |
[1, 1, 1] |
0 | FAULT | None |
| 4 | 2 |
[2, 0, 1] |
[1, 0, 0] |
1 | FAULT | 7 (Clared R0,R1,R2=0) |
| 5 | 0 |
[2, 0, 1] |
[1, 1, 0] |
1 | HIT | None |
| 6 | 3 |
[2, 0, 3] |
[1, 1, 1] |
0 | FAULT | 1 |
| 7 | 0 |
[2, 0, 3] |
[1, 1, 1] |
0 | HIT | None |
| 8 | 4 |
[4, 0, 3] |
[1, 0, 0] |
1 | FAULT | 2 (Cleared R0,R1,R2=0) |
| 9 | 2 |
[4, 2, 3] |
[1, 1, 0] |
2 | FAULT | 0 |
| 10 | 3 |
[4, 2, 3] |
[1, 1, 1] |
2 | HIT | None |
- Total Second Chance Faults: $\mathbf{8 \text{ Page Faults}}$
5. Enhanced Second Chance Algorithm (2-Bit Pair)
- Policy: Uses pair $(R, M)$ where $R = \text{Reference Bit}$, $M = \text{Modify/Dirty Bit}$.
- Class Hierarchy:
(0, 0): Best candidate (Not recently used, clean).(0, 1): Second choice (Not recently used, but modified - requires writeback).(1, 0): Third choice (Recently used, clean).(1, 1): Worst candidate (Recently used and modified).
✏️ Worked Example Trace:
Reference sequence with operations: 7(R), 0(W), 1(R), 2(W), 0(R), 3(W), 0(R), 4(W), 2(R), 3(R) on 3 Frames.
- Step 1-3: Load 7(1,0), 0(1,1), 1(1,0). Frames full.
- Step 4 (2(W)): Scan for Class $(0,0) \implies$ none. Scan for Class $(0,1)$ clearing $R=0$. Finds 7(0,0) $\implies$ Evict 7, load 2(1,1).
- Step 5 (0(R)): Hit on 0. Set $R=1 \implies (1,1)$.
- Step 6 (3(W)): Scan for $(0,0) \implies$ Finds 1(0,0) $\implies$ Evict 1, load 3(1,1).
- Total Faults: 8 Page Faults.
6. LFU (Least Frequently Used)
- Policy: Maintains execution access frequency counter per page. Replaces page with smallest counter. Tie-breaker: FIFO.
✏️ Step-by-Step Execution Trace:
| Step | Ref Page | Frames [F0, F1, F2] |
Frequencies (Page: Count) |
Status | Evicted Page |
|---|---|---|---|---|---|
| 1 | 7 |
[7, -, -] |
7:1 | FAULT | None |
| 2 | 0 |
[7, 0, -] |
7:1, 0:1 | FAULT | None |
| 3 | 1 |
[7, 0, 1] |
7:1, 0:1, 1:1 | FAULT | None |
| 4 | 2 |
[2, 0, 1] |
0:1, 1:1, 2:1 | FAULT | 7 (FIFO tie-break count 1) |
| 5 | 0 |
[2, 0, 1] |
0:2, 1:1, 2:1 | HIT | None |
| 6 | 3 |
[2, 0, 3] |
0:2, 2:1, 3:1 | FAULT | 1 (Tie-break count 1) |
| 7 | 0 |
[2, 0, 3] |
0:3, 2:1, 3:1 | HIT | None |
| 8 | 4 |
[4, 0, 3] |
0:3, 3:1, 4:1 | FAULT | 2 (Tie-break count 1) |
| 9 | 2 |
[4, 0, 2] |
0:3, 4:1, 2:1 | FAULT | 3 (Tie-break count 1) |
| 10 | 3 |
[3, 0, 2] |
0:3, 2:1, 3:1 | FAULT | 4 (Tie-break count 1) |
- Total LFU Faults: $\mathbf{9 \text{ Page Faults}}$
7. MFU (Most Frequently Used)
- Policy: Replaces page with highest access frequency counter (assumes low-count page was just brought in and will be needed). Tie-breaker: FIFO.
✏️ Step-by-Step Execution Trace:
- Step 1-3: Load
7,0,1(Faults 1, 2, 3). Frequencies: 7:1, 0:1, 1:1. - Step 4 (
2): Highest freq tie 1 $\implies$ FIFO evicts7. Load2. (Fault 4). Freqs: 0:1, 1:1, 2:1. - Step 5 (
0): Hit. Frequencies: 0:2, 1:1, 2:1. - Step 6 (
3): Highest freq is0(count 2) $\implies$ Evict 0. Load3. (Fault 5). Freqs: 1:1, 2:1, 3:1. - Step 7 (
0): Highest freq tie 1 $\implies$ FIFO evicts1. Load0. (Fault 6). Freqs: 2:1, 3:1, 0:1. - Step 8 (
4): Evicts2(FIFO tie). Load4. (Fault 7). - Step 9 (
2): Evicts3(FIFO tie). Load2. (Fault 8). -
Step 10 (
3): Evicts0(FIFO tie). Load3. (Fault 9). -
Total MFU Faults: $\mathbf{9 \text{ Page Faults}}$
📊 Master Page Replacement Benchmark Summary Table
| Algorithm | Fault Count (7,0,1,2,0,3,0,4,2,3) |
Hardware Overhead | Belady's Anomaly? | Production OS Implementation |
|---|---|---|---|---|
| Optimal (OPT) | 7 (Minimum) | Theoretical (Needs Future) | Immune | Theoretical Benchmark |
| LRU | 8 | High (Counter / Stack per ref) | Immune | Approximated via Clock |
| Second Chance (Clock) | 8 | Low (1 Bit per frame) | Vulnerable | Linux / Windows Page Replacer |
| Enhanced Second Chance | 8 | Low (2 Bits per frame) | Vulnerable | Windows Memory Manager |
| FIFO | 9 | Minimal (Queue pointer) | Vulnerable | Rarely used standalone |
| LFU | 9 | High (Counter registers) | Vulnerable | Cache Layering |
| MFU | 9 | High (Counter registers) | Vulnerable | Specialized DB engines |
🏛️ Pillar 3: Deadlocks & Banker's Algorithm Masterclass
3.1 The 4 Coffman Conditions for Deadlock
Deadlock occurs if and only if all 4 conditions hold simultaneously: 1. Mutual Exclusion: At least one resource is held in a non-shareable mode. 2. Hold and Wait: A process holds at least one resource and waits for additional resources held by others. 3. No Preemption: Resources cannot be preempted forcibly; released only voluntarily. 4. Circular Wait: Set of waiting processes $\{P_0, P_1, \dots, P_n\}$ such that $P_0$ waits for $P_1$, $P_1$ for $P_2$, ..., and $P_n$ for $P_0$.
3.2 Banker's Algorithm Data Structures & Formulas
Let $n = \text{number of processes}$, $m = \text{number of resource types}$. - $\text{Available}[m]$: Available instances of each resource type. - $\text{Max}[n][m]$: Maximum resource demand of each process. - $\text{Allocation}[n][m]$: Currently allocated instances to each process. - $\text{Need}[n][m]$: Remaining resource need of each process. $$\text{Need}[i][j] = \text{Max}[i][j] - \text{Allocation}[i][j]$$
3.3 Worked Numerical Example 1: Dijkstra's Safety Algorithm
Benchmark System State:
5 Processes ($P_0, P_1, P_2, P_3, P_4$) and 3 Resource Types ($A=10, B=5, C=7$).
| Process | Allocation ($A, B, C$) | Max ($A, B, C$) | Need Matrix ($Need = Max - Alloc$) |
|---|---|---|---|
| $P_0$ | 0, 1, 0 | 7, 5, 3 | $(7-0, 5-1, 3-0) = \mathbf{(7, 4, 3)}$ |
| $P_1$ | 2, 0, 0 | 3, 2, 2 | $(3-2, 2-0, 2-0) = \mathbf{(1, 2, 2)}$ |
| $P_2$ | 3, 0, 2 | 9, 0, 2 | $(9-3, 0-0, 2-2) = \mathbf{(6, 0, 0)}$ |
| $P_3$ | 2, 1, 1 | 2, 2, 2 | $(2-2, 2-1, 2-1) = \mathbf{(0, 1, 1)}$ |
| $P_4$ | 0, 0, 2 | 4, 3, 3 | $(4-0, 3-0, 3-2) = \mathbf{(4, 3, 1)}$ |
Step 1: Compute Initial Available Vector:
$$\text{Total Allocated} = \sum \text{Allocation} = (0+2+3+2+0, 1+0+0+1+0, 0+0+2+1+2) = (7, 2, 5)$$ $$\text{Available} = \text{Total Resources} - \text{Total Allocated} = (10-7, 5-2, 7-5) = \mathbf{(3, 3, 2)}$$
Step 2: Step-by-Step Safety Trace:
Initialize $\text{Work} = (3, 3, 2)$, $\text{Finish} = [\text{False}, \text{False}, \text{False}, \text{False}, \text{False}]$.
- Check $P_0$: $\text{Need}_0 (7, 4, 3) \le \text{Work} (3, 3, 2)$ $\implies \text{FALSE}$. Cannot execute yet.
- Check $P_1$: $\text{Need}_1 (1, 2, 2) \le \text{Work} (3, 3, 2)$ $\implies \mathbf{\text{TRUE}}$.
- Execute $P_1$. New $\text{Work} = \text{Work} + \text{Allocation}_1 = (3,3,2) + (2,0,0) = \mathbf{(5, 3, 2)}$.
- $\text{Finish}[1] = \text{True}$.
- Check $P_3$: $\text{Need}_3 (0, 1, 1) \le \text{Work} (5, 3, 2)$ $\implies \mathbf{\text{TRUE}}$.
- Execute $P_3$. New $\text{Work} = (5,3,2) + (2,1,1) = \mathbf{(7, 4, 3)}$.
- $\text{Finish}[3] = \text{True}$.
- Check $P_4$: $\text{Need}_4 (4, 3, 1) \le \text{Work} (7, 4, 3)$ $\implies \mathbf{\text{TRUE}}$.
- Execute $P_4$. New $\text{Work} = (7,4,3) + (0,0,2) = \mathbf{(7, 4, 5)}$.
- $\text{Finish}[4] = \text{True}$.
- Check $P_0$: $\text{Need}_0 (7, 4, 3) \le \text{Work} (7, 4, 5)$ $\implies \mathbf{\text{TRUE}}$.
- Execute $P_0$. New $\text{Work} = (7,4,5) + (0,1,0) = \mathbf{(7, 5, 5)}$.
- $\text{Finish}[0] = \text{True}$.
- Check $P_2$: $\text{Need}_2 (6, 0, 0) \le \text{Work} (7, 5, 5)$ $\implies \mathbf{\text{TRUE}}$.
- Execute $P_2$. New $\text{Work} = (7,5,5) + (3,0,2) = \mathbf{(10, 5, 7)}$.
- $\text{Finish}[2] = \text{True}$.
$$\text{System is in a SAFE STATE. Safe Execution Sequence: } \mathbf{\langle P_1, P_3, P_4, P_0, P_2 \rangle}$$
3.4 Worked Numerical Example 2: Resource Request Algorithm
Suppose Process $P_1$ makes an additional request: $\text{Request}_1 = (1, 0, 2)$. Can this request be granted immediately?
- Step 1: Is $\text{Request}_1 (1,0,2) \le \text{Need}_1 (1,2,2)$? $\implies \mathbf{\text{TRUE}}$.
- Step 2: Is $\text{Request}_1 (1,0,2) \le \text{Available} (3,3,2)$? $\implies \mathbf{\text{TRUE}}$.
-
Step 3: Pretend to allocate resources: $$\text{Available} = (3,3,2) - (1,0,2) = \mathbf{(2, 3, 0)}$$ $$\text{Allocation}_1 = (2,0,0) + (1,0,2) = \mathbf{(3, 0, 2)}$$ $$\text{Need}_1 = (1,2,2) - (1,0,2) = \mathbf{(0, 2, 0)}$$
-
Step 4: Run Safety Test on Modified State:
- $\text{Work} = (2, 3, 0)$.
- $P_1$: $\text{Need}_1(0,2,0) \le (2,3,0) \implies \text{Run } P_1$. New $\text{Work} = (2,3,0) + (3,0,2) = \mathbf{(5, 3, 2)}$.
- $P_3$: $\text{Need}_3(0,1,1) \le (5,3,2) \implies \text{Run } P_3$. New $\text{Work} = (5,3,2) + (2,1,1) = \mathbf{(7, 4, 3)}$.
- $P_4$: $\text{Need}_4(4,3,1) \le (7,4,3) \implies \text{Run } P_4$. New $\text{Work} = (7,4,3) + (0,0,2) = \mathbf{(7, 4, 5)}$.
- $P_0$: $\text{Need}_0(7,4,3) \le (7,4,5) \implies \text{Run } P_0$. New $\text{Work} = (7,4,5) + (0,1,0) = \mathbf{(7, 5, 5)}$.
- $P_2$: $\text{Need}_2(6,0,0) \le (7,5,5) \implies \text{Run } P_2$. New $\text{Work} = (7,5,5) + (3,0,2) = \mathbf{(10, 5, 7)}$.
$$\mathbf{Conclusion: \text{Request can be GRANTED immediately since system remains safe.}}$$
🏛️ Pillar 4: Process Synchronization, Hardware Primitives, Semaphores & Classical C Code Masterclass
4.1 The Critical Section Problem Criteria
Any concurrent synchronization mechanism must satisfy: 1. Mutual Exclusion: If process $P_i$ is in its critical section, no other process can execute in its critical section. 2. Progress: If no process is in its critical section and some wish to enter, only those processes not executing in their remainder section can participate in deciding who enters next, and this decision cannot be postponed indefinitely. 3. Bounded Waiting: A bound must exist on the number of times other processes are allowed to enter their critical section after a process has requested entry before that request is granted.
4.2 Software Solution: Peterson's Algorithm (2 Processes $P_0, P_1$)
#include <stdbool.h>
// Shared Atomic State
bool flag[2] = {false, false}; // flag[i] = true implies P_i wants to enter CS
int turn = 0; // Whose turn it is to enter CS
void process_P0() {
while (1) {
flag[0] = true; // Express intent to enter
turn = 1; // Yield turn to P1
while (flag[1] && turn == 1); // Busy Wait (Spinlock)
// === CRITICAL SECTION ===
// Access Shared Data safely
// ========================
flag[0] = false; // Exit Critical Section
// Remainder Section
}
}
void process_P1() {
while (1) {
flag[1] = true; // Express intent to enter
turn = 0; // Yield turn to P0
while (flag[0] && turn == 0); // Busy Wait (Spinlock)
// === CRITICAL SECTION ===
// Access Shared Data safely
// ========================
flag[1] = false; // Exit Critical Section
// Remainder Section
}
}
4.3 Hardware Atomic Synchronization Primitives
1. TestAndSet Atomic Instruction
TestAndSet atomically reads the target memory location and sets it to true.
#include <stdbool.h>
// Atomic Hardware Instruction Emulation
bool TestAndSet(bool *target) {
bool rv = *target;
*target = true;
return rv; // Returns original value
}
// Lock Implementation using TestAndSet
bool lock = false;
void acquire_lock() {
while (TestAndSet(&lock)); // Spin until lock becomes false
}
void release_lock() {
lock = false;
}
2. CompareAndSwap (CAS) Atomic Instruction
int CompareAndSwap(int *value, int expected, int new_value) {
int temp = *value;
if (*value == expected) {
*value = new_value;
}
return temp; // Returns original value
}
// Lock Implementation using CAS
int lock_val = 0; // 0 = unlocked, 1 = locked
void lock_cas() {
while (CompareAndSwap(&lock_val, 0, 1) != 0); // Spin until 0 returned
}
void unlock_cas() {
lock_val = 0;
}
4.4 Semaphores Definition & C Pseudocode
A Semaphore $S$ is an integer variable accessed only through two standard atomic operations: wait() (or P()) and signal() (or V()).
typedef struct {
int value;
struct process *queue; // Sleeping process queue
} semaphore;
void wait(semaphore *S) {
S->value--;
if (S->value < 0) {
// Add process to S->queue;
// sleep(); // Block calling thread
}
}
void signal(semaphore *S) {
S->value++;
if (S->value <= 0) {
// Remove process P from S->queue;
// wakeup(P); // Unblock thread
}
}
4.5 ALL 4 Classical Synchronization Problems & Production C Code
1. Bounded Buffer (Producer-Consumer) Problem
- Semaphores:
mutex = 1,empty = N,full = 0.
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#define BUFFER_SIZE 5
int buffer[BUFFER_SIZE];
int in = 0, out = 0;
sem_t empty;
sem_t full;
pthread_mutex_t mutex;
void* producer(void* arg) {
int item = 1;
while (1) {
sem_wait(&empty); // Wait for empty slot
pthread_mutex_lock(&mutex); // Lock buffer
buffer[in] = item;
printf("Producer produced: %d at index %d\n", item, in);
in = (in + 1) % BUFFER_SIZE;
pthread_mutex_unlock(&mutex); // Unlock buffer
sem_post(&full); // Increment full count
item++;
}
}
void* consumer(void* arg) {
while (1) {
sem_wait(&full); // Wait for full slot
pthread_mutex_lock(&mutex); // Lock buffer
int item = buffer[out];
printf("Consumer consumed: %d from index %d\n", item, out);
out = (out + 1) % BUFFER_SIZE;
pthread_mutex_unlock(&mutex); // Unlock buffer
sem_post(&empty); // Increment empty count
}
}
2. Readers-Writers Problem (First Readers-Writers: Reader Preference)
- Semaphores:
rw_mutex = 1,mutex = 1. Shared variable:read_count = 0.
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
int read_count = 0;
pthread_mutex_t mutex; // Protects read_count
sem_t rw_mutex; // Controls writer access
void* reader(void* arg) {
while (1) {
pthread_mutex_lock(&mutex);
read_count++;
if (read_count == 1) {
sem_wait(&rw_mutex); // First reader locks writers out
}
pthread_mutex_unlock(&mutex);
// === READING SECTION ===
printf("Reader is reading shared data...\n");
pthread_mutex_lock(&mutex);
read_count--;
if (read_count == 0) {
sem_post(&rw_mutex); // Last reader allows writers in
}
pthread_mutex_unlock(&mutex);
}
}
void* writer(void* arg) {
while (1) {
sem_wait(&rw_mutex); // Lock out readers and other writers
// === WRITING SECTION ===
printf("Writer is modifying shared data...\n");
sem_post(&rw_mutex); // Release lock
}
}
3. Dining Philosophers Problem
- Setup: 5 Philosophers sitting at a round table with 5 chopsticks (
sem_t chopstick[5]). - Deadlock Avoidance: Odd philosophers pick up left chopstick first; even philosophers pick up right chopstick first.
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <unistd.h>
sem_t chopstick[5];
void* philosopher(void* num) {
int id = *(int*)num;
int left = id;
int right = (id + 1) % 5;
while (1) {
printf("Philosopher %d is thinking...\n", id);
if (id % 2 == 0) {
sem_wait(&chopstick[right]); // Pick up Right first
sem_wait(&chopstick[left]); // Pick up Left second
} else {
sem_wait(&chopstick[left]); // Pick up Left first
sem_wait(&chopstick[right]); // Pick up Right second
}
// === EATING SECTION ===
printf("Philosopher %d is EATING using chopsticks %d and %d\n", id, left, right);
sem_post(&chopstick[left]);
sem_post(&chopstick[right]);
}
}
4. Sleeping Barber Problem
- Setup: Barber shop with 1 Barber chair and $N$ waiting chairs.
- Semaphores:
customers = 0,barbers = 0,mutex = 1. Variable:waiting = 0.
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#define CHAIRS 4
sem_t customers; // Number of waiting customers
sem_t barbers; // Number of idle barbers
pthread_mutex_t mutex;
int waiting = 0;
void* barber(void* arg) {
while (1) {
sem_wait(&customers); // Sleep if no customers waiting
pthread_mutex_lock(&mutex); // Lock waiting chair count
waiting--; // Decr waiting count
sem_post(&barbers); // Barber ready to cut hair
pthread_mutex_unlock(&mutex);
// === CUTTING HAIR ===
printf("Barber is cutting hair...\n");
}
}
void* customer(void* arg) {
pthread_mutex_lock(&mutex);
if (waiting < CHAIRS) {
waiting++;
sem_post(&customers); // Wake up barber if sleeping
pthread_mutex_unlock(&mutex);
sem_wait(&barbers); // Wait for barber to become ready
printf("Customer is getting haircut...\n");
} else {
// No empty chairs available
pthread_mutex_unlock(&mutex);
printf("Customer left: No empty chairs available.\n");
}
}
🏛️ Pillar 5: Complete Disk Scheduling Master Benchmark (All 6 Algorithms)
Benchmark Test Setup:
- Disk Tracks: $0 - 199$ (Total 200 tracks).
- Initial Head Position: 53
- Head Movement Direction: Moving towards Higher Tracks (Right).
- Request Queue:
98, 183, 37, 122, 14, 124, 65, 67
1. FCFS (First-Come, First-Served)
- Path: $53 \to 98 \to 183 \to 37 \to 122 \to 14 \to 124 \to 65 \to 67$
- Step-by-Step Distance Calculation: $$|98 - 53| + |183 - 98| + |37 - 183| + |122 - 37| + |14 - 122| + |124 - 14| + |65 - 124| + |67 - 65|$$ $$= 45 + 85 + 146 + 85 + 108 + 110 + 59 + 2 = \mathbf{640 \text{ tracks}}$$
2. SSTF (Shortest Seek Time First)
- Path: $53 \to 65 \to 67 \to 37 \to 14 \to 98 \to 122 \to 124 \to 183$
- Step-by-Step Distance Calculation: $$|65 - 53| + |67 - 65| + |37 - 67| + |14 - 37| + |98 - 14| + |122 - 98| + |124 - 122| + |183 - 124|$$ $$= 12 + 2 + 30 + 23 + 84 + 24 + 2 + 59 = \mathbf{236 \text{ tracks}}$$
3. SCAN (Elevator Algorithm)
- Behavior: Moves towards track 199 servicing requests, reaches end of disk boundary (199), then reverses direction.
- Path: $53 \to 65 \to 67 \to 98 \to 122 \to 124 \to 183 \to \mathbf{199 \text{ (disk boundary)}} \to 37 \to 14$
- Step-by-Step Distance Calculation: $$(199 - 53) + (199 - 14) = 146 + 185 = \mathbf{331 \text{ tracks}}$$
4. C-SCAN (Circular SCAN)
- Behavior: Moves towards track 199 servicing requests, reaches track 199, jumps instantly to track 0 without servicing, then moves right servicing remaining requests.
- Path: $53 \to 65 \to 67 \to 98 \to 122 \to 124 \to 183 \to \mathbf{199} \to \mathbf{0 \text{ (circular jump)}} \to 14 \to 37$
- Step-by-Step Distance Calculation: $$(199 - 53) + (199 - 0) + (37 - 0) = 146 + 199 + 37 = \mathbf{382 \text{ tracks}}$$
5. LOOK
- Behavior: Moves towards higher requests up to the maximum request (183), then reverses direction without hitting the disk boundary (199).
- Path: $53 \to 65 \to 67 \to 98 \to 122 \to 124 \to 183 \to 37 \to 14$
- Step-by-Step Distance Calculation: $$(183 - 53) + (183 - 14) = 130 + 169 = \mathbf{299 \text{ tracks}}$$
6. C-LOOK (Circular LOOK)
- Behavior: Moves towards higher requests up to maximum request (183), jumps directly to minimum request (14), then moves right.
- Path: $53 \to 65 \to 67 \to 98 \to 122 \to 124 \to 183 \to \mathbf{14 \text{ (circular jump)}} \to 37$
- Step-by-Step Distance Calculation: $$(183 - 53) + (183 - 14) + (37 - 14) = 130 + 169 + 23 = \mathbf{322 \text{ tracks}}$$
📊 Master Disk Scheduling Benchmark Summary Table
| Algorithm | Total Head Movement (Tracks) | Reaches Disk Boundary (199)? | Starvation Risk | Primary Advantage |
|---|---|---|---|---|
| SSTF | 236 (Minimum) | No | High (Wild requests) | Lowest average seek time |
| LOOK | 299 | No | Low | High efficiency without boundary overhead |
| C-LOOK | 322 | No | None | Uniform response time across all tracks |
| SCAN | 331 | Yes (199) | Low | Elevator algorithm, predictable bound |
| C-SCAN | 382 | Yes (199 & 0) | None | Eliminates edge request bias |
| FCFS | 640 (Worst) | No | None | Completely fair, zero scheduling overhead |
🏛️ Pillar 6: 🎯 CoCubes Technical MCQ Master Patterns & High-Yield OS Insights
6.1 CoCubes CPU Scheduling & Gantt Chart Question Patterns
CoCubes technical modules heavily feature conceptual and quick-calculation MCQs on CPU scheduling:
1. Time Quantum ($TQ$) Edge Cases in Round Robin:
- As $TQ \to \infty$: Round Robin degrades into FCFS (First-Come, First-Served).
- As $TQ \to 0$: Round Robin approaches Processor Sharing (pure time sharing), but context-switch overhead approaches $100\%$, drastically lowering CPU throughput.
- Optimal $TQ$ Rule of Thumb: Set $TQ$ such that $80\%$ of CPU bursts finish within a single time quantum.
2. Convoy Effect:
- Occurs in FCFS when a long CPU-bound process holds the processor, forcing multiple short I/O-bound processes to wait in the Ready Queue.
3. Shortest Remaining Time First (SRTF) Preemption Triggers:
- A running process $P_{\text{run}}$ is preempted only when a newly arrived process $P_{\text{new}}$ has a burst time $BT(P_{\text{new}}) < \text{Remaining } BT(P_{\text{run}})$.
- If $BT(P_{\text{new}}) = \text{Remaining } BT(P_{\text{run}})$, preemption does not occur (tie goes to the running process).
6.2 CoCubes Page Replacement & Memory Management Patterns
1. Belady's Anomaly Identification:
- Definition: Page fault rate increases despite increasing the number of physical frame allocations.
- Vulnerable Algorithms: FIFO, Second Chance, Simple Counting Algorithms.
- Immune Algorithms (Stack Algorithms): LRU, Optimal (OPT), LFU/MFU with stack properties.
- Classic CoCubes MCQ Distractor: "Which of the following page replacement algorithms CANNOT exhibit Belady's Anomaly?" $\implies$ LRU / Optimal.
2. Thrashing & Working Set Model:
- Thrashing occurs when the total size of processes' working sets exceeds total physical memory capacity ($\sum WSS_i > D$).
- Symptom: CPU utilization drops to near zero because processes are constantly handling page faults.
- Solution: Decrease the degree of multiprogramming (suspend low-priority processes).
6.3 CoCubes Semaphores & Process Synchronization Patterns
1. Semaphore Operations & Atomic Guarantees:
wait(S)/P(S)Operation:c S.value--; if (S.value < 0) { // add this process to S.queue; // block(); }signal(S)/V(S)Operation:c S.value++; if (S.value <= 0) { // remove a process P from S.queue; // wakeup(P); }- Counting Semaphore Value Interpretation:
- If $S > 0$: $S$ represents the number of available resource instances.
- If $S < 0$: $|S|$ represents the exact number of processes currently blocked in the semaphore waiting queue.
2. Mutex vs Counting Semaphore:
- Mutex (Binary Semaphore): Initialized to
1. Used strictly for Mutual Exclusion (ownership enforced: only the thread that locked the mutex can unlock it). - Counting Semaphore: Initialized to
N. Used for Resource Counting (any thread can executesignal()).