Bird
Raised Fist0
FreeRTOSprogramming~10 mins

Recursive mutex for nested locking in FreeRTOS - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - Recursive mutex for nested locking
Task tries to lock mutex
↓
Is mutex free?
No→Is current task owner?
↓
Increase lock count
↓
Task does work
↓
Task unlocks mutex
↓
Decrease lock count
↓
Is lock count zero?
No→Mutex still owned
Yes↓
Release mutex ownership
↓
Unblock waiting tasks if any
↓
Done
The task tries to lock the mutex. If free, it locks and sets owner. If already owned by the same task, it increases a count. Unlocking decreases count and releases ownership when count hits zero.
Execution Sample
FreeRTOS
void task_function() {
  xSemaphoreTakeRecursive(mutex, portMAX_DELAY);
  // critical section
  xSemaphoreGiveRecursive(mutex);
}
A task locks a recursive mutex, does work, then unlocks it.
Execution Table
StepActionMutex OwnerLock CountTask StateOutput
1Task tries to lock mutexNone0RunningMutex free, lock granted
2Mutex locked by taskTask11RunningLock count = 1
3Task tries to lock mutex again (nested)Task11RunningOwner matches, increment count
4Lock count incrementedTask12RunningLock count = 2
5Task unlocks mutex onceTask12RunningDecrement lock count
6Lock count decrementedTask11RunningLock count = 1
7Task unlocks mutex againTask11RunningDecrement lock count
8Lock count decremented to zeroNone0RunningMutex released, owner cleared
9Mutex freeNone0RunningOther tasks can lock now
💡 Lock count reached zero, mutex ownership released, task finished nested locking
Variable Tracker
VariableStartAfter Step 2After Step 4After Step 6After Step 8Final
Mutex OwnerNoneTask1Task1Task1NoneNone
Lock Count012100
Task StateRunningRunningRunningRunningRunningRunning
Key Moments - 3 Insights
Why does the lock count increase when the same task locks the mutex again?
Because the mutex is recursive, the same task can lock it multiple times without blocking. The lock count tracks how many times it has locked it (see steps 3 and 4 in execution_table).
What happens if a different task tries to lock the mutex while it is owned?
The other task will block until the mutex is fully released (lock count zero). This is implied in the flow but not shown in this trace because only one task locks it.
Why is the mutex ownership only released when lock count reaches zero?
Because the mutex must be unlocked as many times as it was locked by the same task. Only then is it free for others (see steps 7 and 8).
Visual Quiz - 3 Questions
Test your understanding
Look at the execution table, what is the lock count after the task locks the mutex the second time?
A2
B1
C0
D3
💡 Hint
Check step 4 in the execution_table where the lock count increments after nested locking.
At which step does the mutex ownership get released?
AStep 4
BStep 6
CStep 8
DStep 9
💡 Hint
Look for when lock count reaches zero and owner is cleared in the execution_table.
If the task only locked the mutex once and then unlocked it, what would the lock count be after unlocking?
A1
B0
C2
DUndefined
💡 Hint
Refer to the variable_tracker and execution_table steps where lock count decrements to zero after unlocking.
Concept Snapshot
Recursive mutex allows the same task to lock multiple times.
Each lock increments a count.
Each unlock decrements the count.
Mutex ownership releases only when count is zero.
Other tasks block until mutex is free.
Use xSemaphoreTakeRecursive and xSemaphoreGiveRecursive in FreeRTOS.
Full Transcript
This visual trace shows how a recursive mutex works in FreeRTOS. When a task locks the mutex, if it is free, the task becomes the owner and the lock count is set to 1. If the same task locks it again, the count increases, allowing nested locking without blocking. Unlocking decreases the count. Only when the count reaches zero is the mutex ownership released, allowing other tasks to lock it. This prevents deadlocks when the same task needs to enter critical sections multiple times. The execution table tracks each step, showing the owner, lock count, and task state. Key moments clarify why the count increments and when ownership is released. The quiz tests understanding of lock count changes and mutex release timing.

Practice

(1/5)
1.

What is the main advantage of using a recursive mutex in FreeRTOS?

easy
A. It increases the priority of the task holding the mutex.
B. It automatically unlocks after a fixed time.
C. It allows the same task to lock the mutex multiple times without deadlock.
D. It can be shared between tasks without any locking.

Solution

  1. Step 1: Understand mutex behavior

    Normal mutexes block if the same task tries to lock again, causing deadlock.
  2. Step 2: Role of recursive mutex

    Recursive mutexes allow the same task to lock multiple times safely, avoiding deadlock.
  3. Final Answer:

    It allows the same task to lock the mutex multiple times without deadlock. -> Option C
  4. Quick Check:

    Recursive mutex = multiple locks by same task [OK]
Hint: Recursive mutex lets one task lock repeatedly safely [OK]
Common Mistakes:
  • Thinking mutex unlocks automatically
  • Confusing recursive mutex with priority inheritance
  • Assuming mutex can be shared without locking
2.

Which FreeRTOS function is used to lock a recursive mutex?

SemaphoreHandle_t xMutex = xSemaphoreCreateRecursiveMutex();
// Lock the mutex here
easy
A. xSemaphoreTakeRecursive(xMutex, portMAX_DELAY);
B. xSemaphoreGiveRecursive(xMutex);
C. xSemaphoreTake(xMutex, portMAX_DELAY);
D. xSemaphoreCreateMutex();

Solution

  1. Step 1: Identify locking function for recursive mutex

    Recursive mutexes require xSemaphoreTakeRecursive() to lock safely multiple times.
  2. Step 2: Match function usage

    xSemaphoreTakeRecursive(xMutex, portMAX_DELAY) locks the recursive mutex properly.
  3. Final Answer:

    xSemaphoreTakeRecursive(xMutex, portMAX_DELAY); -> Option A
  4. Quick Check:

    Lock recursive mutex = xSemaphoreTakeRecursive() [OK]
Hint: Use xSemaphoreTakeRecursive() to lock recursive mutex [OK]
Common Mistakes:
  • Using xSemaphoreTake() instead of recursive version
  • Confusing give and take functions
  • Trying to create mutex again instead of locking
3.

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");
    }
}
medium
A. Mutex fully released
B. Mutex still locked
C. Compilation error
D. Deadlock occurs

Solution

  1. Step 1: Count lock and unlock calls

    The mutex is locked twice and unlocked twice, so it is fully released after two gives.
  2. Step 2: Analyze extra unlock call

    The third give returns pdFALSE because mutex is already fully released, triggering "Mutex fully released" print.
  3. Final Answer:

    Mutex fully released -> Option A
  4. Quick Check:

    Extra unlock returns false = fully released [OK]
Hint: Unlock same times as lock to fully release mutex [OK]
Common Mistakes:
  • Assuming extra unlock succeeds
  • Ignoring return value of xSemaphoreGiveRecursive()
  • Thinking deadlock occurs on unlock
4.

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);
}
medium
A. Not locking the mutex before unlocking.
B. Using xSemaphoreGive() instead of xSemaphoreGiveRecursive() to unlock.
C. Creating mutex inside the task instead of globally.
D. Using portMAX_DELAY as timeout.

Solution

  1. Step 1: Check unlock function for recursive mutex

    Recursive mutexes must be unlocked with xSemaphoreGiveRecursive(), not xSemaphoreGive().
  2. Step 2: Identify mismatch in lock/unlock

    Using xSemaphoreGive() causes undefined behavior or errors because it is for normal mutexes.
  3. Final Answer:

    Using xSemaphoreGive() instead of xSemaphoreGiveRecursive() to unlock. -> Option B
  4. Quick Check:

    Unlock recursive mutex = xSemaphoreGiveRecursive() [OK]
Hint: Unlock recursive mutex with xSemaphoreGiveRecursive() only [OK]
Common Mistakes:
  • Mixing normal and recursive mutex functions
  • Ignoring correct unlock function
  • Assuming portMAX_DELAY causes error here
5.

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
hard
A. Call xSemaphoreTakeRecursive() again to balance locks.
B. Call xSemaphoreGiveRecursive() once to release the mutex fully.
C. Call xSemaphoreGive() three times to release the mutex.
D. Call xSemaphoreGiveRecursive() exactly three times before releasing the mutex.

Solution

  1. Step 1: Understand recursive mutex lock count

    Each lock increments a count; unlocking must decrement the same number of times.
  2. Step 2: Proper unlock calls

    To fully release, call xSemaphoreGiveRecursive() three times matching the three locks.
  3. Final Answer:

    Call xSemaphoreGiveRecursive() exactly three times before releasing the mutex. -> Option D
  4. Quick Check:

    Unlock count = lock count to avoid deadlock [OK]
Hint: Unlock recursive mutex as many times as locked [OK]
Common Mistakes:
  • Unlocking fewer times causing deadlock
  • Using xSemaphoreGive() instead of recursive version
  • Trying to unlock more times than locked
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard