The problem in one sentence
You already know from the previous rung that a process spends most of its life Ready or Waiting, not Running, and that the CPU is handed from one process to another by a context switch. So picture the ready queue right now: a dozen processes all loaded, all complete, all willing to run — and exactly one free CPU. Somebody has to point at one of them and say you go next. That single recurring decision is CPU scheduling, and the part of the kernel that makes it is the short-term scheduler. It is the building manager deciding which tenant gets the one working elevator each time the doors open.
It is worth pausing on why this is even necessary. If every process needed the CPU non-stop from start to finish, scheduling would be trivial: line them up, run one to completion, run the next. The reason scheduling is interesting — and the reason it makes your machine fast — is that real programs almost never need the CPU continuously. They run for a little while, then stop and wait for something. Understanding that stop-and-wait rhythm is the whole foundation, so let us look at it next.
Bursts: the rhythm that makes scheduling pay off
Watch any process closely and you see a repeating two-beat rhythm called the CPU–I/O burst cycle. A CPU burst is a stretch where the process is computing — adding numbers, comparing strings, running a loop — and genuinely wants the CPU. Then it hits something it cannot do itself: it asks to read a file with read(fd, buf, n), or waits for a key press, or sends data over the network. Now begins an I/O burst, during which the process is blocked in the Waiting state, holding the CPU hostage for nobody, while a disk or network does the slow work. Then the I/O finishes, the process wakes up, and the next CPU burst begins. Compute, wait, compute, wait — over and over until it exits.
process P over time: |== CPU ==| (read) ....I/O wait.... |= CPU =| (read) ...I/O... |==CPU==| exit compute block disk busy compute block net compute CPU bursts are usually SHORT and MANY; I/O bursts are LONG.
Here is the punchline. The instant a process blocks for I/O, its CPU would otherwise sit idle, doing nothing, for the entire slow wait. That idle time is the opportunity. While process P waits on the disk, the scheduler can hand the CPU to process Q, which is ready to compute right now. When P's data arrives, P rejoins the ready queue. By interleaving many processes' CPU bursts into each other's I/O gaps, the OS keeps the CPU busy almost all the time — this is exactly the old idea of multiprogramming, and scheduling is the mechanism that makes it work. Without bursts, there would be no gaps to fill and no reason to schedule.
The dispatcher: muscle, not brain
It helps to separate two jobs that beginners often blur. The scheduler is the brain: it decides which process should run next, by some policy. The dispatcher is the muscle: once the choice is made, the dispatcher actually puts that process onto the CPU. The scheduler answers who; the dispatcher does the how. They are different because the policy of choosing can be clever and slow-changing, while the act of switching must be the same fast, mechanical routine every single time.
- Perform the context switch: save the outgoing process's registers into its PCB, and load the incoming process's saved registers (you saw this exact step in the previous rung).
- Switch the memory mappings to the new process's address space, so its (page number, offset) addresses now point to its own memory.
- Switch the CPU from kernel mode back to user mode, dropping the elevated privileges the kernel needed to do all this.
- Jump to exactly the instruction the new process was about to run last time, and let it go. The new process never notices it was paused.
The time from the moment the scheduler decides to stop one process until the moment the chosen one is actually running is called dispatch latency, and we want it as small as possible. Why? Because every microsecond the dispatcher spends shuffling registers is a microsecond in which NO user program is getting work done. The dispatcher is pure overhead — the stagehand changing the set between scenes, while the audience waits and no acting happens. A good dispatcher is invisible precisely because it is fast.
Preemptive or not: when may we interrupt?
A scheduler also needs a rule about timing: may it yank the CPU away from a running process, or must it wait politely until that process gives it up? This is the preemptive versus non-preemptive distinction. A non-preemptive (or cooperative) scheduler only reschedules when the running process voluntarily stops — when it blocks for I/O or exits. Once you start running, the CPU is yours until you choose to release it. A preemptive scheduler, by contrast, can forcibly take the CPU back, typically when a timer interrupt fires — the doorbell that tells the kernel time is up.
The trade-off is real, and honest naming matters. Non-preemptive scheduling is simple and avoids some nasty bugs (you never get interrupted mid-update of shared data by the scheduler), but it is fragile: a single misbehaving process that loops forever and never blocks will hog the CPU and freeze everything else. Preemptive scheduling is what makes a system feel responsive and fair — your typing still registers even while a heavy program runs — but it costs more switches and forces the kernel to be careful about race conditions, because a process can now be stopped at any awkward moment. Almost every interactive OS today is preemptive; the doorbell is always armed.
The five yardsticks: judging a scheduler
Before we can compare algorithms in the next guides, we need to agree on what good even means. There is no single perfect scheduler, because the goals pull against each other; the scheduling criteria are the five standard yardsticks we measure by. CPU utilization is the fraction of time the CPU is doing useful work rather than sitting idle (we want it high). Throughput is how many processes complete per unit of time (high is good). The other three are measured per process and we want them low: turnaround time is total time from submission to completion; waiting time is just the time spent sitting in the ready queue; and response time is the time from submission until the process FIRST starts producing output.
The last two are subtly different and the gap between them is where scheduler design lives. Waiting time and response time both start the same clock, but response time stops as soon as the process produces its first visible result, whereas waiting time accumulates over the process's whole life. For an interactive task — your text editor reacting to a keystroke — response time is what you feel; you do not care that the editor finishes its full job in 30 ms, you care that the cursor moved within 50 ms of your tap. For a batch job grinding through a billion rows, you do not feel response time at all; you only care about turnaround. A scheduler tuned for snappy response is often tuned AGAINST raw throughput, and vice versa.
Where this rung is heading
You now have the whole frame. Scheduling exists because the burst pattern leaves CPU gaps worth filling; the scheduler decides who runs while the dispatcher carries out the switch with low dispatch latency; the system is usually preemptive so it stays fair and responsive; and we judge every choice against five yardsticks. Everything else in this rung is just different answers to the same question — given the ready queue, who goes next? — each making a different bargain among those yardsticks.
Next we will meet the two simplest ideas and feel their flaws first-hand: first-come-first-served, which seems fair until one giant job causes a traffic jam behind it, and shortest-job-first, which is provably optimal for waiting time yet needs a fact it cannot truly know — how long each job will run. After that come round robin and its all-important time quantum, then priorities with their danger of starvation, and finally the real-world schedulers that knit these ideas together. One question, many bargains; let us start trading.