Task Starvation and Priority Inversion in FreeRTOS
📖 Scenario: You are working on a FreeRTOS-based embedded system where multiple tasks share a resource. You want to understand how task starvation and priority inversion can happen and how to detect them.
🎯 Goal: Build a simple FreeRTOS program with three tasks of different priorities sharing a mutex. Observe how priority inversion can cause task starvation and learn how to use priority inheritance to fix it.
📋 What You'll Learn
Create three tasks: HighPriorityTask, MediumPriorityTask, and LowPriorityTask
Use a mutex called xMutex to protect a shared resource
Demonstrate priority inversion by having LowPriorityTask hold the mutex while HighPriorityTask waits
Add priority inheritance to the mutex to prevent starvation
Print messages to the console to show task execution order
💡 Why This Matters
🌍 Real World
Embedded systems often have tasks with different priorities sharing resources. Understanding priority inversion helps avoid delays in critical tasks.
💼 Career
Embedded software engineers must manage task priorities and synchronization to ensure real-time system responsiveness and reliability.
Progress0 / 4 steps
1
Create three tasks and a mutex
Create a mutex called xMutex using xSemaphoreCreateMutex(). Then create three tasks named LowPriorityTask, MediumPriorityTask, and HighPriorityTask with priorities 1, 2, and 3 respectively. Use xTaskCreate() for each task. Do not start the scheduler yet.
FreeRTOS
Hint
Use xSemaphoreCreateMutex() to create the mutex. Use xTaskCreate() to create each task with the correct priority.
2
Add mutex locking in LowPriorityTask
Modify LowPriorityTask to take the mutex xMutex using xSemaphoreTake() before printing "Low priority task running". Hold the mutex for 3000 milliseconds using vTaskDelay(), then release it with xSemaphoreGive(). Keep the other tasks unchanged.
FreeRTOS
Hint
Use xSemaphoreTake(xMutex, portMAX_DELAY) to wait for the mutex. Print the message, delay for 3000 ms, then release the mutex with xSemaphoreGive(xMutex).
3
Make HighPriorityTask try to take the mutex and print messages
Modify HighPriorityTask to try taking the mutex xMutex with xSemaphoreTake() using portMAX_DELAY. When it gets the mutex, print "High priority task running", then release the mutex with xSemaphoreGive(). Add a short delay of 1000 milliseconds after releasing the mutex. Keep MediumPriorityTask unchanged.
FreeRTOS
Hint
Use xSemaphoreTake(xMutex, portMAX_DELAY) to wait for the mutex. Print the message, release the mutex, then delay 1000 ms.
4
Enable priority inheritance and observe output
Modify the mutex creation to enable priority inheritance by using xSemaphoreCreateMutex() (already done). Run the program and print the messages from all tasks to observe how priority inversion is resolved. Add print statements in MediumPriorityTask to print "Medium priority task running" every 1000 milliseconds. Finally, print the messages from all tasks to the console.
FreeRTOS
Hint
In MediumPriorityTask, add a print statement inside the infinite loop and delay 1000 ms each time.
Practice
(1/5)
1. What does task starvation mean in FreeRTOS?
easy
A. Some tasks never get CPU time because others run too much
B. All tasks get equal CPU time regardless of priority
C. Tasks run in a random order without priority
D. Tasks share CPU time only when a mutex is free
Solution
Step 1: Understand task scheduling in FreeRTOS
FreeRTOS schedules tasks based on priority, so higher priority tasks run more often.
Step 2: Define task starvation
Task starvation happens when low priority tasks never get CPU time because higher priority tasks keep running.
Final Answer:
Some tasks never get CPU time because others run too much -> Option A
Quick Check:
Task starvation = some tasks starve for CPU [OK]
Hint: Starvation means some tasks get no CPU time [OK]
Common Mistakes:
Confusing starvation with equal CPU sharing
Thinking tasks run randomly
Assuming mutex controls CPU time directly
2. Which FreeRTOS API is used to create a mutex that supports priority inheritance?
easy
A. xQueueCreate()
B. xSemaphoreCreateMutex()
C. vTaskDelay()
D. xTaskCreate()
Solution
Step 1: Identify mutex creation functions
FreeRTOS uses xSemaphoreCreateMutex() to create mutexes with priority inheritance.
Step 2: Differentiate other APIs
xQueueCreate() creates queues, vTaskDelay() delays tasks, and xTaskCreate() creates tasks, not mutexes.
Final Answer:
xSemaphoreCreateMutex() -> Option B
Quick Check:
Mutex with priority inheritance = xSemaphoreCreateMutex() [OK]
Hint: Mutex with priority inheritance uses xSemaphoreCreateMutex() [OK]
Common Mistakes:
Choosing xQueueCreate() for mutex
Confusing task creation with mutex creation
Using delay functions instead of mutex APIs
3. Given three tasks with priorities High (3), Medium (2), and Low (1). Low task holds a mutex needed by High task. What happens without priority inheritance?
medium
A. Medium task is blocked until High task finishes
B. Low task immediately releases the mutex
C. High task waits indefinitely while Medium task runs
D. High task preempts Low task and runs
Solution
Step 1: Understand priority inversion scenario
Low priority task holds mutex needed by High priority task, so High task blocks waiting.
Step 2: Effect without priority inheritance
Medium priority task runs, preventing Low task from running and releasing mutex, causing High task to wait indefinitely.
Final Answer:
High task waits indefinitely while Medium task runs -> Option C
Quick Check:
Priority inversion without inheritance = High task blocked [OK]
Hint: Without inheritance, medium task blocks low task, blocking high task [OK]
Common Mistakes:
Assuming low task releases mutex immediately
Thinking high task preempts low task despite mutex
Believing medium task is blocked
4. Identify the problem in this FreeRTOS code snippet causing priority inversion: