Side-by-side comparison
| Parameter | Preemptive | Cooperative RTOS |
|---|---|---|
| Switch Trigger | Timer tick (configTICK_RATE_HZ) or higher-priority ready event | Task calls taskYIELD(), vTaskDelay(), or blocks on queue/semaphore |
| Context Switch Rate | Every tick (default 1 ms in FreeRTOS); also on unblock | Only when task voluntarily yields — could be seconds |
| Response to Higher-Priority Task | Immediate — within one tick period | Only after currently running task yields |
| Worst-Case Latency | 1 tick period (1 ms default) + ISR latency | Unbounded — depends on task cooperation |
| Stack Usage | Higher — each task must save full context on preemption | Lower — context only saved at explicit yield points |
| Developer Discipline Required | Low — system works even if tasks block inadvertently | High — every task must yield frequently; one bug stalls all |
| FreeRTOS Config | configUSE_PREEMPTION = 1 (default) | configUSE_PREEMPTION = 0 |
| Suitable for Hard Real-Time | Yes — deterministic worst-case response | No — latency depends on task behaviour |
| Typical Use Case | Production firmware: drones, industrial, medical devices | Cooperative multitasking on very small MCUs; contiki-style OS |
| Risk of Priority Inversion | Present — requires mutex with priority inheritance | Not applicable — no involuntary preemption |
Key differences
Preemptive scheduling switches context on every FreeRTOS tick (default 1 ms) and immediately on any event that unblocks a higher-priority task — worst-case latency is bounded to one tick period regardless of what lower-priority tasks are doing. Cooperative scheduling only switches when the running task calls vTaskDelay() or taskYIELD() — a task with a busy loop or an inadvertent while(flag) spin stalls every lower-priority task permanently. Preemptive mode costs slightly more stack RAM per task because the full CPU context (16 registers on Cortex-M) must be saved on any tick interrupt. Cooperative mode is used in Contiki OS for 8-bit sensors nodes with 2 kB RAM where saving a full context on every tick is too expensive.
When to use Preemptive
Use cooperative scheduling only on severely memory-constrained 8-bit MCUs (< 4 kB RAM) where task context-save overhead is a measurable fraction of available RAM and all developers can be trusted to yield frequently. Example: a Contiki OS node on an ATmega128 (4 kB RAM) uses cooperative protothreads to manage six sensor tasks with only 50 bytes overhead per protothread.
When to use Cooperative RTOS
Use preemptive scheduling for any production firmware where deterministic response time is required or multiple developers share the codebase. Example: a FreeRTOS STM32H743 medical infusion pump runs five tasks (pump control, alarm, UI, logging, comms) with preemption enabled at 1 kHz tick; a blocking bug in the UI task cannot stall the pump control task because the scheduler preempts it within 1 ms.
Recommendation
For any safety-critical, multi-developer, or real-time application, choose preemptive scheduling — latency guarantees and fault isolation from misbehaving tasks are non-negotiable. Choose cooperative only when RAM is so tight that the per-task context save overhead (64 bytes on Cortex-M) is unaffordable. This is rare on any ARM-based MCU produced after 2015.
Exam tip: Examiners ask students to state the maximum context switch latency in preemptive FreeRTOS given a tick rate of 1000 Hz and an ISR latency of 5 µs — answer: 1 ms (tick period) + 5 µs ISR latency = approximately 1.005 ms worst case.
Interview tip: An RTOS interviewer at a safety-critical product company will ask you to define the difference between preemptive and cooperative scheduling and state which is required for an IEC 62443 or IEC 61508 safety-rated firmware — answer: preemptive; cooperative cannot guarantee bounded response time required by functional safety standards.