EmbeddedRelated.com

Preemption

Category: Rtos | Also known as: preemptive, pre-emption, preemptive multitasking

Preemption is the act of suspending a currently running task mid-execution so that a higher-priority task or interrupt can run immediately. In a preemptive multitasking system, the scheduler — not the running task — decides when control is transferred. (ISRs are similarly preemptible, but by higher-priority hardware interrupts rather than by the RTOS scheduler.)

In practice

In a preemptive RTOS such as FreeRTOS, Zephyr, or embOS, the scheduler can context-switch away from a running task whenever a higher-priority task becomes ready — for example, when an ISR posts a semaphore or sends a message to a queue. This switch can happen immediately on such an event; a timer tick is one common trigger but not the only one. The preempted task's register state and stack pointer are saved so it can resume later as if nothing happened. This is in contrast to cooperative multitasking, where a task runs until it voluntarily yields.

Preemption is what makes bounded response times achievable on most embedded RTOS targets. If a sensor-reading task unblocks a high-priority control loop task, the control loop can get CPU time very quickly (within one scheduler tick at most on tick-triggered implementations, though the exact latency depends on configuration) rather than waiting for the lower-priority task to finish. This bounded latency is the core reason to choose a preemptive RTOS over a simple cooperative scheduler or a super-loop, though cooperative and cyclic-executive designs can also meet real-time requirements when workloads are tightly bounded.

A major source of bugs in preemptive systems is shared mutable state. Any data that is concurrently mutated by more than one task — or by both a task and an ISR — requires protection such as a mutex, critical section, or atomic operation. Read-only shared data generally does not need protection; the hazard arises from concurrent writes or non-atomic read-modify-write sequences. Forgetting this is one of the most common sources of intermittent, hard-to-reproduce failures in embedded firmware. The blog post "Blocking == Technical Debt" discusses how blocking calls in tasks interact with the scheduler and can compound these hazards.

Preemption also interacts with interrupt handling. On ARM Cortex-M cores, the NVIC supports nested interrupt preemption independently of the RTOS task scheduler: a higher-priority interrupt can preempt a lower-priority ISR at the hardware level, before the RTOS is even involved. Understanding the distinction between hardware interrupt preemption and RTOS task preemption is important; the blog post "Cutting Through the Confusion with ARM Cortex-M Interrupt Priorities" covers the Cortex-M priority model in detail.

Frequently asked

What is the difference between preemptive and cooperative multitasking?
In cooperative multitasking, tasks run until they explicitly yield control — the scheduler cannot forcibly suspend them. In preemptive multitasking, the scheduler can suspend a running task at any time (typically on a timer tick or on an event) and switch to a higher-priority ready task. Preemptive systems provide tighter worst-case response times but require careful use of synchronization primitives to protect shared data.
Does enabling preemption mean my system will have race conditions?
Preemption creates the conditions under which race conditions can occur, but it does not make them inevitable. Any resource shared between tasks of different priorities must be protected — using a mutex, semaphore, critical section, or atomic operation. If all shared state is properly protected, a preemptive system can be safe. The risk is that it is easy to overlook sharing, especially with global variables.
Can an ISR preempt an RTOS task?
Yes. On most MCUs, hardware interrupts preempt tasks regardless of RTOS task priorities. On ARM Cortex-M cores, an interrupt fires as soon as the hardware accepts it, suspending whatever task or lower-priority ISR was running. The RTOS task scheduler only becomes involved again after the ISR returns — at which point a context switch may occur if the ISR made a higher-priority task ready.
What is priority inversion and how does it relate to preemption?
Priority inversion is a condition where a high-priority task is effectively blocked by a low-priority task because both contend for the same resource (e.g., a mutex). The high-priority task cannot preempt its way past the resource hold. It can be mitigated with priority inheritance (supported by mutex implementations in FreeRTOS, Zephyr, and others), which temporarily raises the low-priority task's priority while it holds the resource.
Do I always need a preemptive RTOS for real-time work?
Not always. Simple systems with a small number of tasks and well-bounded execution times can meet timing requirements with a cooperative scheduler, a cyclic executive (super-loop with timing slots), or even a carefully structured bare-metal design. The blog post 'You Don't Need an RTOS (Part 1)' explores when a simpler approach is sufficient. A preemptive RTOS adds overhead and complexity, so it is worth confirming you need the response-time guarantees it provides before adopting one.

Differentiators vs similar concepts

Preemption is often conflated with multitasking in general. Multitasking simply means running multiple tasks; it can be cooperative or preemptive. Preemption specifically refers to the involuntary suspension of a running task by the scheduler or by a hardware interrupt. It is also distinct from time-slicing: time-slicing is a specific preemption policy where tasks of equal priority each get a fixed CPU quantum in round-robin fashion, whereas preemption can also occur immediately on a priority change regardless of how long the current task has been running.