03. Scheduling in Interactive Systems

Unlike batch architectures that maximize total computational throughput, desktop operating systems, mobile devices, and multi-tenant web servers operate under user scrutiny. In interactive environments, the primary metric is Response Time (Tresponse)—the delay between a user action (keystroke, tap, network packet arrival) and the visible system response.

1. Round-Robin (RR) Scheduling

Round-Robin is the oldest, simplest, and most reliable preemptive scheduling algorithm designed for time-sharing systems:

The Quantum Sizing Dilemma

The choice of time quantum length q fundamentally controls the balance between raw throughput and interactive responsiveness:

Figure 3.1: The Quantum Sizing Spectrum
Context switch overhead fraction α = δ / (q + δ) versus interactive responsiveness.
Tiny Quantum (q = 2 ms) Exec: 2ms Switch: 1ms • Context overhead: 33% lost! • Severe cache & TLB thrashing Optimal Quantum (q = 20 ms) Exec: 20 ms • Low overhead: <5% wasted • Smooth UI response (<50ms) Huge Quantum (q = 500 ms) Exec: 500 ms • Near-zero switch overhead • Degenerates into FCFS (Lag!) Rule of thumb: Set q slightly longer than 80% of interactive CPU bursts.

Turnaround vs. Response Trade-off in Round-Robin

While Round-Robin provides exceptional fairness and guarantees an upper bound on response time (with n processes and quantum q, no process waits longer than (n − 1) × q time units before its next slice), its average turnaround time is often substantially worse than Shortest Job First.

If three processes with burst lengths of 10 ms run under RR with q = 1 ms, all three complete nearly simultaneously around T = 28, 29, and 30 ms (average turnaround ≈ 29 ms). Under SJF, they complete at 10, 20, and 30 ms (average turnaround = 20 ms). Round-Robin deliberately sacrifices average turnaround time to ensure immediate response times for all tasks.

2. Priority Scheduling & Dynamic Aging

In production systems, processes are not created equal. A critical window manager rendering 120 FPS display frames must preempt a background virus scanner. Priority scheduling assigns each task a priority integer, and the scheduler dispatches the highest-priority runnable process first.

The Priority Inversion Dilemma

Strict priority scheduling introduces a lethal synchronization vulnerability known as Priority Inversion:

  1. Low-priority task L acquires a shared lock/mutex (e.g., sound device driver).
  2. High-priority task H arrives and attempts to acquire the mutex. Because L holds the lock, H blocks.
  3. Medium-priority task M (which does not need the lock) becomes runnable. Because Priority(M) > Priority(L), M preempts L and runs continuously.
  4. The Inversion: Task L cannot finish its critical section to release the lock because M is monopolizing the CPU. High-priority task H is indirectly starved by medium-priority task M!

Solution (Priority Inheritance Protocol, PIP): When task H blocks waiting for a lock held by L, the kernel temporarily boosts task L's priority to match H. Task L runs with high priority, completes its critical section rapidly, releases the lock, drops back to its base priority, and allows H to run immediately.

Dynamic Aging to Eliminate Starvation

To prevent low-priority background processes from starving indefinitely when a stream of high-priority interactive tasks exists, schedulers implement dynamic aging. The effective priority is calculated as:

Peffective = Pbase + k × Twait

As a task waits in the Ready queue, its priority climbs steadily. Eventually, its effective priority surpasses active interactive tasks, guaranteeing that every process receives CPU time.

3. Multi-Level Feedback Queues (MLFQ)

Corbato's Multi-Level Feedback Queue (MLFQ) is the foundational discipline of modern general-purpose schedulers. Its objective is to solve the fundamental scheduling dilemma: how can a scheduler optimize turnaround time (like SJF) and minimize response time (like RR) without any prior knowledge of job lengths?

MLFQ learns from the past behavior of a process to predict its future behavior, establishing a hierarchy of distinct priority queues (e.g., Q0 at top priority down to Q2 at bottom priority).

The Five Fundamental MLFQ Rules

Why Rule 4 & Rule 5 are Critical:
Preventing Gaming of the Scheduler: Early MLFQ implementations reset a process's quantum if it voluntarily yielded for I/O before the quantum expired. Malicious or poorly designed programs exploited this by running for 99% of the quantum, issuing a trivial I/O call, yielding the CPU, and staying at top priority forever. Rule 4 tracks cumulative CPU consumption, demoting tasks once their allotment expires regardless of yielding.

Adapting to Phase Changes & Starvation: Rule 5 solves two problems: (1) it guarantees that long batch compute jobs sitting at the bottom queue cannot starve, and (2) if a compute-bound job transitions into an interactive phase (e.g., waiting for user input after completing a calculation), the priority boost gives it an opportunity to prove its new interactive behavior.

Interactive Stepper: MLFQ Execution & Allotment Accounting

Workload Arc Process A (Compute-Bound Loop) and Process B (Loop yielding at 9ms) execute under MLFQ. Tracking dynamic queue demotion and anti-gaming protection.
Active Core Entity Process A (New Arrival)
Active Queue Level Queue Q0 (Quantum = 10ms)
Consumed Allotment 0 ms / 10 ms
Time to Priority Boost 100 ms Remaining
QUEUE Q0 [High Priority | Quantum = 10ms] QUEUE Q1 [Medium Priority | Quantum = 20ms] QUEUE Q2 [Batch / Compute | Quantum = 40ms] CPU CORE 0 Running: Process A Process A (Compute) Queue: Q0 (Top) Allotment: 0 / 10ms Status: Running burst
Current Step Summary Process A enters the system. Per Rule 3, it is placed into Queue Q0 with an initial 10ms quantum allotment.
What Is Happening

Process A enters top queue Q0. The scheduler optimistically assumes the task is short and interactive, granting it immediate CPU access.

Why The System Does This

Placing unknown jobs at the top queue minimizes response time for interactive tasks while requiring zero prior declarations.

4. Proportional-Share & Lottery Scheduling

Every scheduler examined so far (FCFS, SJF, SRTN, Round-Robin, and MLFQ) operates on a priority or latency premise: they evaluate process queue states to answer the immediate operational question: "Which specific process should run next to optimize turnaround time or user responsiveness?"

Proportional-Share scheduling (also called Fair-Share scheduling) abandons this framing entirely. Instead of optimizing for completion deadlines or interface responsiveness, it treats CPU execution bandwidth as an economic resource. Its foundational question is:

"How can the operating system guarantee that over time, Process A receives exactly 75% of the processor's silicon capacity, while Process B receives exactly 25%?"

1. Lottery Scheduling: The Randomized Raffle

Pioneered by Carl Waldspurger and William Weihl, Lottery Scheduling uses probabilistic randomness to achieve proportional resource division:

Kernel Implementation: The Linked-List Traversal

A common misconception is that the kernel maintains a massive array containing millions of ticket numbers. In real operating systems, ticket tracking requires minimal memory: the scheduler maintains a linked list of runnable tasks, where each task's PCB simply stores its single integer ticket allocation.

/* Kernel Lottery Selection Algorithm: O(N) Traversal */
int total_tickets = 100;
int winning_ticket = random_int(0, total_tickets - 1); /* e.g., draws 82 */
int counter = 0;
struct task_struct *curr = ready_list_head;

while (curr != NULL) {
    counter += curr->tickets;
    if (counter > winning_ticket) {
        /* Found the task owning the winning range! */
        switch_to(curr);
        break;
    }
    curr = curr->next;
}
Tracing the Silicon Dispatch Logic:
Suppose Process A has 75 tickets and Process B has 25 tickets. Total tickets = 100.
The winning draw is 82: To maximize algorithmic efficiency, kernels sort the ready list in descending order of tickets (placing high-ticket tasks at the front), minimizing average traversal steps.
Ticket Mechanics in Practice

2. The Problem with Pure Randomness: Scheduling Jitter

The fundamental flaw of lottery scheduling is short-term variance (jitter).

While the Law of Large Numbers guarantees that a 75/25 ticket split will converge to an exact 3:1 ratio over millions of cycles, randomness does not guarantee fairness over short time windows. Just as flipping a fair coin can produce four heads in a row, Process B (the 25% task) might randomly win five consecutive draws.

If Process A is rendering a video stream or handling real-time audio playback, losing several lottery draws in a row introduces noticeable stutter and dropped audio frames.

3. Stride Scheduling: Deterministic Fair-Share

To preserve the exact proportional guarantees of lottery scheduling while completely eliminating random variance, Waldspurger designed Stride Scheduling.

The Race & Odometer Metaphor

Think of Stride Scheduling as a race where runners take strides of different lengths:

  1. Pick a Large System Constant (K): For example, K = 10,000.
  2. Calculate Each Process's Stride: The stride is inversely proportional to its ticket allocation:
    Stridei = K / Ticketsi
    For Process A (75 tickets): StrideA = 10,000 / 75 ≈ 133.
    For Process B (25 tickets): StrideB = 10,000 / 25 = 400.
  3. Maintain an Execution Odometer (the pass value): Every process tracks its progress using a pass counter (initialized to 0).
  4. The Dispatch Invariant: The scheduler always selects the process with the minimum pass value. After that process executes for one quantum, its pass counter advances by its stride:
    passi += Stridei
Deterministic Step-by-Step Execution Trace
Tick Pass Counters Prior to Dispatch Task Selected (MIN pass) Pass Counter Update
0 Pass(A) = 0, Pass(B) = 0 Process A (Tie-break) Pass(A) = 0 + 133 = 133
1 Pass(A) = 133, Pass(B) = 0 Process B Pass(B) = 0 + 400 = 400
2 Pass(A) = 133, Pass(B) = 400 Process A Pass(A) = 133 + 133 = 266
3 Pass(A) = 266, Pass(B) = 400 Process A Pass(A) = 266 + 133 = 399
4 Pass(A) = 399, Pass(B) = 400 Process A Pass(A) = 399 + 133 = 532
5 Pass(A) = 532, Pass(B) = 400 Process B Pass(B) = 400 + 400 = 800

Notice the resulting execution order: A, B, A, A, A, B. Over these 6 intervals, Process A executes 4 times and Process B executes 2 times. As time proceeds, the ratio converges precisely to 3:1 (75% vs. 25%) with zero randomness, zero jitter, and deterministic predictability.

Figure 3.2: Lottery List Traversal vs. Stride Progress Tracking
Comparing the probabilistic ticket list traversal against the deterministic pass counter odometer.
LOTTERY SCHEDULING (Random Draw: 82) Process A: Tickets 0 – 74 (75% Pool) B: 75–99 Task A (75 tkts) sum=75 < 82 (Skip) Task B (25 tkts) sum=100 > 82 (WIN!) • Non-deterministic; subject to random clustering. • Memory-efficient O(N) linked list walk. STRIDE SCHEDULING (Deterministic Pass Values) Task A (75 tickets) Stride = 10,000/75 = 133 Task B (25 tickets) Stride = 10,000/25 = 400 Pass Progression: A: 133 → 266 → 399 B: 400 → 800 • Always pick MIN(pass); zero random variance.

4. Modern Lineage: Linux CFS & Container Fair-Share

Why do operating systems courses teach Stride and Lottery scheduling if general-purpose desktop operating systems do not roll dice?

Because Stride Scheduling is the direct conceptual ancestor of modern cloud virtualization and container resource management: