Recursive mutex is a regular mutex, but allows a task to take the mutex multiple times without blocking itself as a semaphore counter but with the advantages of mutex. When a task successfully takes the same recursive mutex multiple times, it must also give the mutex back the same number of times. The mutex remains unavailable to other tasks until the owner has given it back for each successful take operation.

Recursive mutexes are used for recursive mutual exclusion and resource management. Help to prevent priority inversion by allowing a task to hold the mutex while calling other functions that might also need the same mutex.


💡
Note: To use Recursive Mutex, File FreeRTOSConfig.h must be edited. Some defines must be set to 1.
#define configUSE_MUTEXES                       1
#define configUSE_RECURSIVE_MUTEXES             1

Recursive mutexes cannot be used from within interrupt service routines (ISRs).


Code Example:

#include "bsp.h"

#define MAX_LEDS 8

SemaphoreHandle_t  xMutex;  /* Mutex semaphore */
uint8_t LEDpin[MAX_LEDS] = { GPIO_PIN_0, GPIO_PIN_1, GPIO_PIN_2, GPIO_PIN_3, GPIO_PIN_4, GPIO_PIN_5, GPIO_PIN_6, GPIO_PIN_7 }; /* Array of LED pins */

void Task1( void *pvParameters );   /* Task1 To turn on LEDs */
void Task2( void *pvParameters );   /* Task2 to turn off LEDs */

int main( void )
{
    HAL_Init();

    SEGGER_SYSVIEW_Conf( );
    SEGGER_SYSVIEW_Start( );

    xMutex = xSemaphoreCreateRecursiveMutex();                 /* Creation of recoursive mutex */ 
    
    xTaskCreate( Task1, "Task_LED_ON", 240, NULL, 2, NULL );   /* Register Task1 to turn on LEDs */
    xTaskCreate( Task2, "Task_LED_OFF", 240, NULL, 1, NULL );  /* Register Task2 to turn off LEDs */
    
    vTaskStartScheduler();                                     /* Init the Kernel */
}

void Task1( void *pvParameters )
{
    UNUSED(pvParameters);
    static uint8_t Iter = 0;                                            /* Variable to increment and change the LED iteration */
    
    for(;;)
    {
        if( Iter < MAX_LEDS )                                           /* Check if variable is lower that the max number of leds to iterate */
        {
            if (xSemaphoreTakeRecursive(xMutex, 0) == pdTRUE )          /* Check if Mutex semaphore is available to increment mutexes taken */
            {
                HAL_GPIO_WritePin(GPIOC, LEDpin[Iter], GPIO_PIN_SET);   /* Turn on the LED */
                SEGGER_SYSVIEW_PrintfHost( "LED ON %d", Iter );     
                Iter++;                                                 /* Increment iteration to change the LED */
            }
        }
        else                                                            /* If iteration is greater than the max number of LEDs */
        {
            for(uint8_t i=0; i < MAX_LEDS; i++)                         /* Execute a for loop to give all the mutexes */
            {
                xSemaphoreGiveRecursive(xMutex);                        /* Give the recoursive mutex */
            }
            Iter = 0;                                                   /* Restart Counter iteration */
        }

        vTaskDelay(200);                                                /* Period Delay of the task */
    }
}

void Task2( void *pvParameters )
{
    UNUSED(pvParameters);
    static uint8_t Iter = 0;                                            /* Variable to increment and change the LED iteration */
    
    for(;;)
    {
        if( Iter < MAX_LEDS )
        {
            if (xSemaphoreTakeRecursive(xMutex, 0) == pdTRUE )          /* Check if variable is lower that the max number of leds to iterate */
            {
                HAL_GPIO_WritePin(GPIOC, LEDpin[Iter], GPIO_PIN_RESET); /* Turn off the LEDs */
                SEGGER_SYSVIEW_PrintfHost( "LED OFF %d", Iter );
                Iter++;                                                 /* Change the LED */
            }
        }
        else                                                            /* If iteration reach the max number of LEDs */
        {
            for(uint8_t i=0; i < MAX_LEDS; i++)                         /* For loop to give recoursive mutex */
            {
                xSemaphoreGiveRecursive(xMutex);                        /* Give the recoursive mutex */
            }
            Iter = 0;                                                   /* Restart counter iteration */
        }

        vTaskDelay(200);                                                /* Period Delay of the task */
    }  
}

For example, in this application are registered 2 task, that going to turn on a series of LEDs and the other task must turn off the LEDs, to control a dynamic execution task going to take a recoursive mutex. Observe the code, task1 is executed take a recoursive mutex each execution, task 2 is blocked waiting to task 1 to unlock the recoursive mutex, Task 1 execute normally until iteration matches with the max number of LEDs, at this point the Task 1 take the same mutex 7 times the number of LEDs, the next execution Task 1 release all the mutex taken and restart the iteration count and task 1 finishes. When task 2 is executed works similarly to Task 1 but this time the LED is Turned off.

SysteView Output

The terminal shows the tasks execution, notice that in the first image, Task1 is running taking the mutex each time that executes and printing which LED is turned on. When Task1 finishes release all the mutex and Task2 can now execute, observe the second image, now the task takes the mutex and turns off the LEDs.

Document

Timeline:

Document

Task1 is running taking the mutex each execution, the first image shows the Task1 execution when an LED is turned on.
The second image shows the next execution of Task1 after the elapsed time of the period. Taking the mutex and turn on the next LED.
Notice in both images, the execution of Task2 that is blocked by the mutex.



When Task1 finishes, release all the mutex taken to unlock the Task2 execution. Task2 going to take mutex each execution until each LED is turned off.
Now the Task1 is blocked for Task2 until it releases all the mutex taken.