We’re Officially Live β€” Lifetime Founding Membership Available for a Limited Time
Free preview

Preemptive vs Round-Robin Scheduling

How the scheduler chooses: priority preemption (urgent runs first), round-robin time-slicing among equal priorities, and cooperative scheduling, plus the starvation and fairness tradeoffs.

22 min read

In this lesson:

The previous lesson said "run the highest-priority Ready task." This lesson is how the scheduler actually arbitrates.


Three scheduling policies

Policy Who runs next Switch trigger
Preemptive priority the highest-priority Ready task, always a higher-priority task becomes Ready β†’ immediate switch
Round-robin equal-priority tasks take turns a time-slice (tick) expires
Cooperative the running task, until it yields the task voluntarily blocks/yields

Real RTOSes blend these. FreeRTOS's default is preemptive priority with round-robin time-slicing among equal priorities, so priority decides who, and round-robin shares the CPU among ties.


Preemptive priority: responsiveness

The core rule: the highest-priority Ready task always runs, and the instant a higher-priority task becomes Ready it preempts the current one, even mid-function.

priorities:  high = sensor(3)   low = log(1)
 
  log running ──────────╳ preempted! ──────────▢ log resumes
                        β–²
              ISR makes sensor Ready (data arrived)
  sensor:               └─runs immediatelyβ”€β”€β”˜

This is what makes an RTOS responsive: an urgent event (via an ISR giving a semaphore, say) gets the CPU within a context switch, no matter what low-priority work was running. The cost is that low-priority tasks can be starved if higher-priority tasks stay Ready (a busy high task β†’ lower tasks never run, the never-block hazard from the last lesson).


Round-robin: fairness among equals

What if two tasks have the same priority and both are Ready? Pure priority can't choose. Round-robin time-slices: each runs for one tick, then yields to the next equal-priority task, cycling fairly.

two tasks at priority 2, time-sliced on each tick:
  tick:  | A | B | A | B | A | B | ...

So in FreeRTOS the two policies stack: priority first (a priority-3 task always beats priority-2), and round-robin only among the equal-priority Ready set at the top. Time-slicing is configurable (configUSE_TIME_SLICING).


Cooperative: simple but fragile

In cooperative scheduling the running task keeps the CPU until it chooses to yield (block or call taskYIELD()); the scheduler never forcibly preempts. (FreeRTOS offers this via configUSE_PREEMPTION = 0.)

Cooperative scheduling is essentially the disciplined super-loop with extra structure; preemptive is what you want for hard responsiveness.


The tradeoffs

flowchart LR
  P[Preemptive priority] -->|+| R1[responsive: urgent preempts instantly]
  P -->|βˆ’| S1[starvation: low priority can be locked out]
  RR[Round-robin] -->|+| F[fair sharing among equals]
  RR -->|βˆ’| O[switch overhead; not deadline-aware]
  C[Cooperative] -->|+| L[simpler, fewer races]
  C -->|βˆ’| H[one bad task hangs all; no forced preemption]

Priority assignment is the real lever: give the tightest-deadline work the highest priority, keep high-priority tasks short and blocking, and group truly-equal peers at one priority to share via round-robin.


Gotchas


TL;DR

This is just the start

Sign up free to track progress on this lesson, get coding problems with the Run button, and unlock the full interview Q&A.

More in RTOS & Real-Time Concepts

Bare-Metal vs RTOSTasks & the Scheduler
Context Switching
Mutexes & Semaphores
Queues & Inter-Task Communication
Priority Inversion