Look at your phone’s clock icon, a WhatsApp notification, music playing, a browser with twenty tabs and an antivirus scanning in the background: everything “at once”. Yet each core (the physical unit that actually executes instructions) can only run one instruction at a single instant. The magic is not in the chip but in an operating-system component that shares its time with millisecond precision: the process scheduler.
From cooperative turns to preemption
The first multitasking PCs used a cooperative model: each program had to willingly hand over the CPU when it finished its work. If a program fell into an infinite loop, the whole system froze and only a reboot brought it back. The fix was preemptive multitasking: programs no longer need to be polite, because a piece of hardware —the timer interrupt, which fires an electrical signal periodically— pokes the kernel every few milliseconds so it regains control no matter what.
The exam every time you switch
Every process lives in a structure called the PCB (Process Control Block), which holds its complete state: the values of the CPU registers, the program counter (the address of the next instruction), the stack pointer, its priorities and the resources it has open. When its turn arrives, the kernel saves all that into the departing process’s PCB and loads the incoming one’s: this is the famous context switch. Each switch costs microseconds of pure overhead, which is why the scheduler fights to make as few as possible.
Quantum: the unfair clock
The scheduler divides time into slices called time slices or quantum, normally in the tens of milliseconds. When the quantum runs out, the timer interrupt calls the kernel, which decides whether the process gets one more step or hands the turn to the next one in the queue. The trick is that the process decides nothing: the OS is always in charge — hence “preemption”.
A tree that decides who runs
Modern Linux uses a scheduler called the CFS (Completely Fair Scheduler). Rather than scanning the whole process list for the fairest candidate, it keeps all ready processes in a red-black tree (a balanced binary search tree that guarantees logarithmic, O(log n) lookups). Each process carries a virtual runtime counter —the CPU time it “deserves” given how many siblings are competing— and the algorithm always picks the node with the least accumulated time, making sure nobody hogs the chip.
Priorities, real time and starvation
Not all processes run equally. The nice value (from −20, top priority, to +19, the lowest) tunes how much CPU an ordinary process gets. On top of that, real-time processes (SCHED_FIFO and SCHED_RR) run before any normal process. This has a dangerous flip side: a high-priority process that never sleeps can cause starvation, literally leaving CPU-hungry processes without a turn. The kernel addresses this with mechanisms such as priority inheritance to avoid priority inversion.
Many cores, many queues
On a multicore processor this multiplies: each core has its own run queue. The kernel’s load balancing moves processes between cores so none sits idle while another piles up work. And with hyperthreading (SMT, Simultaneous Multi-Threading) one physical core presents two logical threads to the system: they share the same execution units but duplicate the registers, better hiding memory latency.
Why it matters to you
Every time a system feels “fluid”, what you are sensing is a scheduler doing its job in fractions of a second. The next time the task manager lights up red, you will know there is no single culprit: there is an umpire with a stopwatch deciding, a thousand times per second, which program deserves the next turn.





