What is Priority Inversion?
Priority inversion can occur in a pre-emptive, multitasking operating system when a high priority task is blocked because a low priority task has the resource it’s waiting for but has itself been pre-empted by a medium priority task. Consider the diagram below:
Task t3 is a low priority task. It takes a mutex guarding a resource and then gets pre-empted by the high priority task t1. As it continues executing, t1 tries to take the mutex and fails as it’s already being help by t3.
t1 pends as it waits for the mutex and the scheduler allows t3 to continue executing. In the meantime a medium priority task, t2, becomes ready to run and pre-empts t3. This stops t3 from releasing the mutex and forces t1 to wait, potentially indefinitely.
How to solve priority inversion?
There are several strategies for avoiding/removing priority inversion from your system. One of the easiest to implement is Priority Inheritance. It works by temporarily raising the priority of a task so it runs at the same priority as the task waiting on the resource.
in the example above, when t1 pends on the mutex, t3 will be boosted to run at the same priority as t1. t2 is now prevented from executing as it can no longer pre-empt t3. As t3 continues to run, it releases the mutex and it’s priority is lowered to it’s original level once more. t1 takes the mutex as soon as it becomes available and pre-empts t3. Meanwhile, t2, although ready to run is prevented from doing so as it’s a lower priority than t1.
Priority inversion is a very common issue with the pre-emptive, multi-tasking operating systems commonly used in embedded software development. When designing your task model it’s always advisable to pay very close attention to the interaction between tasks especially where they may pend on a resource.
Using good programming practices and making use of techniques such as priority inheritance is a must to avoid problems downstream.