Lecture 3 of 1418 minInteractiveFree lecture

CPU scheduling

With more runnable tasks than CPU cores, the scheduler decides who runs next and for how long. Simulate three classic policies on the same workload and see the trade-offs between throughput, waiting time and responsiveness.

In this lecture you will

  • Explain what a scheduler decides and when it runs
  • Calculate turnaround, waiting and response time for a schedule
  • Compare first-come first-served, shortest job first and round robin
  • Relate scheduling to real systems, including Linux and container CPU limits

In the last lecture, processes waited in the ready state for a CPU. With a few cores and hundreds of runnable threads, the kernel faces a question thousands of times a second: who runs next, and for how long? The part of the kernel that answers it is the scheduler.

What “good” means

There is no single best schedule, because the goals conflict:

Turnaround time
From arrival to completion. Matters for batch jobs such as reports and builds.
Waiting time
Time spent ready but not running. The part scheduling can actually improve.
Response time
From arrival until the task first runs. What users feel in interactive systems.
Throughput
Jobs completed per unit of time. Reduced by switching overhead.
Fairness
Every task gets a reasonable share; nothing starves forever.

Three classic policies

  • First-come, first-served (FCFS) runs jobs to completion in arrival order. Simple, predictable — and prone to the convoy effect, where short jobs wait behind a long one.
  • Shortest job first (SJF) always picks the ready job with the smallest remaining work. It provably minimizes average waiting time, but requires knowing job lengths in advance and can starve long jobs.
  • Round robin (RR) gives each ready job a fixed time slice (quantum) in turn, then pre-empts it and moves it to the back of the queue. Everyone makes progress quickly, which suits interactive systems.

Simulate them

Four processes arrive at different times with different amounts of work. Switch policies and watch the Gantt chart and the metrics. For round robin, change the time slice.

InteractiveCPU scheduling simulatorSwitch policy and slice length
Loading visual…

When new arrivals and a pre-empted process become ready at the same moment, new arrivals are queued first — a common convention.

Notice the pattern. SJF gives the lowest average waiting time. Round robin gives the best response times — every process starts soon after it arrives — but finishes some jobs later and needs more context switches. A large time slice makes round robin behave like FCFS; a tiny one drowns in overhead.

What real kernels do

Production schedulers blend these ideas with extra goals such as multiple cores, priorities and power saving:

  • Priorities and fairness. Linux’s general-purpose scheduler aims to give each runnable task a fair share of CPU time, weighted by its priority (its nice value). Tasks that have run less recently get to run sooner.
  • Interactive boosts. Tasks that often sleep waiting for input tend to get the CPU quickly when they wake, keeping desktops and terminals snappy.
  • Multiple cores. Each core has its own run queue, and the kernel balances load between them — while trying to keep tasks on the same core so their data stays in that core’s caches.
  • Real-time classes. Some tasks, such as audio processing, need strict deadlines and can be given scheduling classes that always run before normal tasks.

Fair sharing by weight is easy to see. Give three busy tasks different nice values — lower means more important — and watch both their shares and the order in which a fair scheduler runs them:

InteractiveNice values and fair sharesChange the nice values
Loading visual…

The weights are the Linux kernel’s own table (nice 0 = 1024). The timeline replays the core rule of a fair scheduler: run the task that has received the least weighted CPU time so far. On Linux, renice changes a running process’s nice value; ordinary users can only make their processes nicer.

See it happen. A service gets a burst of work and spreads it over several threads, inside a container with a CPU limit:

InteractiveWhy a CPU limit can hurt latencyChange the limit and the threads
Loading visual…

With a limit of 1 core, four busy threads spend the 100 ms quota in 25 ms and then wait 75 ms for the next period. Averaged over a second, the container used a quarter of a core — dashboards look calm while requests take several times longer. On Linux, cpu.stat in the container’s cgroup counts the throttled periods.

So far, one task runs at a time per core. The next lecture looks at what goes wrong when several threads run at the same time and share data.

Key takeaways

  • The scheduler picks which ready task runs on each core, and pre-empts tasks when their time slice ends.
  • Different goals conflict — short average waiting time, fast response, fairness and low overhead.
  • Shortest job first minimizes average waiting time but needs job lengths in advance and can starve long jobs.
  • Round robin trades some throughput for responsiveness; the time slice balances fairness against context-switch overhead.

Check your understanding

3 questions · answers explained

Q1Why does first-come, first-served often give poor average waiting time?

This is the convoy effect. One long job at the front of the queue makes every shorter job behind it wait, inflating the average.

Q2What happens in round robin if the time slice is made extremely small?

Tiny slices mean the CPU switches constantly. Each switch costs time and cache warmth, so a larger fraction of CPU time is wasted on overhead rather than useful work.

Q3A containerized service has a CPU limit and shows high latency even though average CPU usage looks low. What is a likely cause?

CPU limits are enforced per short period. Bursty workloads can exhaust the quota quickly and then be throttled until the next period — invisible in averages but painful for latency.