Here, I will explain these three concepts from a simple and microcontroller engineer’s perspective, ensuring you understand them at a glance.
๐ 1. Preemptive Scheduler
Core: Tasks can be “forcefully interrupted”, and the CPU’s control can be taken away by higher priority tasks at any time.
โ Features
- Uses interrupts + priority to control task switching
- When a high-priority task arrives โ immediately interrupts the current task
- RTOS (FreeRTOS, RTX) all use this mechanism
- Each task has its own stack and context switching
โ Applicable Scenarios
- Strong real-time requirements
- Multiple tasks running in parallel without blocking each other
- Complex logic projects (e.g., communication + control + interface)
โ Example
PWM interrupt needs to execute every 20ยตs โ it can interrupt the main loop at any time, which is “preemption”.
โ The essence: relies on hardware interrupts to preempt the CPU
โฑ 2. Time Slice Round-Robin / Time Polling
Core: The CPU will not be interrupted; tasks can only “queue and take turns executing”, each running a little bit.
โ Features
- Non-preemptive
- Different tasks are executed in order
- Each task runs for a short period (time slice), then switches to the next
- No interrupts means no task switching (except SysTick)
โ Typical Performance in Microcontrollers
Like this:
while (1) {
Task_A();
Task_B();
Task_C();
}
Or:
if (Sched_Every(&t1, 1)) Task_A();
if (Sched_Every(&t2, 5)) Task_B();
Both are polling style.
โ Advantages / Disadvantages
- Simple structure, very stable
- Delays rely on “queuing” โ not real-time enough
- If one task gets stuck โ all other tasks get stuck
โ The essence: queuing to do things in a big loop, will not be forcefully interrupted.
๐ฑ 3. Coroutines
Core: Tasks voluntarily yield the CPU, not preempted, but “voluntary switching”.
โ Features
- Lightweight, does not require an independent stack (there are stack coroutines, but the overhead is much less)
- Does not rely on interrupts, will not preempt
- Tasks execute to a certain point and then yield() / await() to yield the CPU
- When continuing execution, it resumes from the last paused point
โ Essential Differences
- Coroutines: I pause voluntarily
- Time slice round-robin: The CPU tells me to pause (when the time slice is up)
- Preemptive: Interrupts directly take the CPU
โ Example in Microcontrollers (State Machine + Segmented Execution)
Like this:
switch(state) {
case 0: ... state=1; break;
case 1: ... state=2; break;
case 2: ... state=0; break;
}
This is actually a manual coroutine โ executing a little bit each time, using state to save the “pause point”.
๐ฅ Comparison of the Three (Microcontroller Perspective)
| Feature | Preemptive Scheduling (RTOS) | Time Slice Round-Robin | Coroutines |
| CPU Control | Can be interrupted and taken at any time | Cannot be taken | Task voluntarily yields |
| Real-time Performance | โญโญโญโญโญ | โญโญ | โญโญโญ |
| Deadlock Risk | Yes (needs locking) | Very low | Low |
| Overhead | Maximum | Minimum | Very small |
| Number of Tasks | Many | Medium | Many |
| Suitable For | Complex systems | Small systems | Lightweight multitasking, logical flow |
๐ The Simplest Summary in One Sentence
Preemptive Scheduling
๐ “I don’t care what you’re doing, high priority needs to use it, yield immediately!
Time Slice Round-Robin
๐ “Everyone comes one by one, queue and take turns on the CPU.
Coroutines
๐ “I do it halfway, pause for a moment, let others go first.