A recursive mutex lets a task lock the same mutex multiple times without causing a deadlock. This helps when a function calls another function that also locks the same mutex.
Recursive mutex for nested locking in FreeRTOS
/* Create a recursive mutex */ SemaphoreHandle_t xRecursiveMutex = xSemaphoreCreateRecursiveMutex(); /* Lock the recursive mutex */ if (xSemaphoreTakeRecursive(xRecursiveMutex, portMAX_DELAY) == pdTRUE) { // Critical section xSemaphoreGiveRecursive(xRecursiveMutex); // Unlock }
Use xSemaphoreCreateRecursiveMutex() to create a recursive mutex.
Use xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() to lock and unlock recursively.
SemaphoreHandle_t xRecursiveMutex = xSemaphoreCreateRecursiveMutex(); // Lock once xSemaphoreTakeRecursive(xRecursiveMutex, portMAX_DELAY); // Lock again (nested) xSemaphoreTakeRecursive(xRecursiveMutex, portMAX_DELAY); // Unlock once xSemaphoreGiveRecursive(xRecursiveMutex); // Unlock second time xSemaphoreGiveRecursive(xRecursiveMutex);
// Edge case: Unlocking without locking first SemaphoreHandle_t xRecursiveMutex = xSemaphoreCreateRecursiveMutex(); xSemaphoreGiveRecursive(xRecursiveMutex); // Incorrect usage, may cause error
// Edge case: Single lock and unlock
SemaphoreHandle_t xRecursiveMutex = xSemaphoreCreateRecursiveMutex();
xSemaphoreTakeRecursive(xRecursiveMutex, portMAX_DELAY);
xSemaphoreGiveRecursive(xRecursiveMutex);// Edge case: Empty mutex handle SemaphoreHandle_t xRecursiveMutex = NULL; if (xRecursiveMutex != NULL) { xSemaphoreTakeRecursive(xRecursiveMutex, portMAX_DELAY); xSemaphoreGiveRecursive(xRecursiveMutex); } else { // Handle error: mutex not created }
This program creates a recursive mutex and a task that locks it multiple times recursively. It prints messages when locking and unlocking at each level.
#include "FreeRTOS.h" #include "semphr.h" #include "task.h" #include <stdio.h> SemaphoreHandle_t xRecursiveMutex; void nestedFunction(int level) { if (xSemaphoreTakeRecursive(xRecursiveMutex, portMAX_DELAY) == pdTRUE) { printf("Locked mutex at level %d\n", level); if (level < 3) { nestedFunction(level + 1); // Recursive nested locking } xSemaphoreGiveRecursive(xRecursiveMutex); printf("Unlocked mutex at level %d\n", level); } } void vTaskFunction(void *pvParameters) { printf("Task started\n"); nestedFunction(1); printf("Task finished\n"); vTaskDelete(NULL); } int main(void) { xRecursiveMutex = xSemaphoreCreateRecursiveMutex(); if (xRecursiveMutex == NULL) { printf("Failed to create recursive mutex\n"); return 1; } xTaskCreate(vTaskFunction, "Task", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL); vTaskStartScheduler(); // Should never reach here return 0; }
Time complexity: Locking and unlocking a recursive mutex is O(1).
Space complexity: Uses small fixed memory for the mutex handle.
Common mistake: Forgetting to unlock the mutex the same number of times it was locked causes deadlocks.
Use recursive mutexes only when nested locking is needed; otherwise, use normal mutexes for better performance.
Recursive mutexes allow the same task to lock the mutex multiple times safely.
Use xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() to lock and unlock.
Always unlock the mutex the same number of times it was locked to avoid deadlocks.
Practice
What is the main advantage of using a recursive mutex in FreeRTOS?
Solution
Step 1: Understand mutex behavior
Normal mutexes block if the same task tries to lock again, causing deadlock.Step 2: Role of recursive mutex
Recursive mutexes allow the same task to lock multiple times safely, avoiding deadlock.Final Answer:
It allows the same task to lock the mutex multiple times without deadlock. -> Option CQuick Check:
Recursive mutex = multiple locks by same task [OK]
- Thinking mutex unlocks automatically
- Confusing recursive mutex with priority inheritance
- Assuming mutex can be shared without locking
Which FreeRTOS function is used to lock a recursive mutex?
SemaphoreHandle_t xMutex = xSemaphoreCreateRecursiveMutex();
// Lock the mutex here
Solution
Step 1: Identify locking function for recursive mutex
Recursive mutexes require xSemaphoreTakeRecursive() to lock safely multiple times.Step 2: Match function usage
xSemaphoreTakeRecursive(xMutex, portMAX_DELAY) locks the recursive mutex properly.Final Answer:
xSemaphoreTakeRecursive(xMutex, portMAX_DELAY); -> Option AQuick Check:
Lock recursive mutex = xSemaphoreTakeRecursive() [OK]
- Using xSemaphoreTake() instead of recursive version
- Confusing give and take functions
- Trying to create mutex again instead of locking
What will be the output of the following FreeRTOS code snippet?
SemaphoreHandle_t xMutex = xSemaphoreCreateRecursiveMutex();
void Task(void *params) {
xSemaphoreTakeRecursive(xMutex, portMAX_DELAY);
xSemaphoreTakeRecursive(xMutex, portMAX_DELAY);
xSemaphoreGiveRecursive(xMutex);
xSemaphoreGiveRecursive(xMutex);
if (xSemaphoreGiveRecursive(xMutex) == pdFALSE) {
printf("Mutex fully released\n");
} else {
printf("Mutex still locked\n");
}
}Solution
Step 1: Count lock and unlock calls
The mutex is locked twice and unlocked twice, so it is fully released after two gives.Step 2: Analyze extra unlock call
The third give returns pdFALSE because mutex is already fully released, triggering "Mutex fully released" print.Final Answer:
Mutex fully released -> Option AQuick Check:
Extra unlock returns false = fully released [OK]
- Assuming extra unlock succeeds
- Ignoring return value of xSemaphoreGiveRecursive()
- Thinking deadlock occurs on unlock
Identify the error in this FreeRTOS recursive mutex usage:
SemaphoreHandle_t xMutex = xSemaphoreCreateRecursiveMutex();
void Task(void *params) {
xSemaphoreTakeRecursive(xMutex, portMAX_DELAY);
// Some code
xSemaphoreGive(xMutex);
}Solution
Step 1: Check unlock function for recursive mutex
Recursive mutexes must be unlocked with xSemaphoreGiveRecursive(), not xSemaphoreGive().Step 2: Identify mismatch in lock/unlock
Using xSemaphoreGive() causes undefined behavior or errors because it is for normal mutexes.Final Answer:
Using xSemaphoreGive() instead of xSemaphoreGiveRecursive() to unlock. -> Option BQuick Check:
Unlock recursive mutex = xSemaphoreGiveRecursive() [OK]
- Mixing normal and recursive mutex functions
- Ignoring correct unlock function
- Assuming portMAX_DELAY causes error here
You have a recursive mutex locked three times by the same task. What must you do to avoid deadlock when unlocking?
// Pseudocode
xSemaphoreTakeRecursive(xMutex, portMAX_DELAY);
xSemaphoreTakeRecursive(xMutex, portMAX_DELAY);
xSemaphoreTakeRecursive(xMutex, portMAX_DELAY);
// ... critical section ...
// Unlock here
Solution
Step 1: Understand recursive mutex lock count
Each lock increments a count; unlocking must decrement the same number of times.Step 2: Proper unlock calls
To fully release, call xSemaphoreGiveRecursive() three times matching the three locks.Final Answer:
Call xSemaphoreGiveRecursive() exactly three times before releasing the mutex. -> Option DQuick Check:
Unlock count = lock count to avoid deadlock [OK]
- Unlocking fewer times causing deadlock
- Using xSemaphoreGive() instead of recursive version
- Trying to unlock more times than locked
Ready to prove it?
Pass the test and this pattern moves unknown
