FreeRTOS mutual exclusion semaphore (mutex lock)

1. Mutually exclusive semaphore

A mutually exclusive semaphore is actually a binary semaphore with priority inheritance, which is mostly used for mutually exclusive access to shared resources between different tasks.

2. Mutual exclusion semaphore reduces the impact of priority flipping

When a mutex semaphore is being used by task L, and a task H also attempts to obtain the mutex semaphore, it will be blocked. However, this task H will raise the priority of task L to the same priority as itself. This process is priority inheritance. Priority inheritance reduces the time that high-priority tasks are blocked as much as possible and minimizes the impact of “priority flips” that have already occurred.

serial number

illustrate

(1)

Task H and task M are in a blocked state, waiting for a certain event to occur. At this time, task L is running.

(2)

At this time, if task L wants to access the shared resource, it needs to obtain a mutex lock. At the same time, the system will pull the priority of L to the same as H.

(3)

Task L successfully acquires the mutex lock. At this time, the lock is already occupied, and Task L begins to access the shared resource.

(4)

When the time slice cycle time is up, task H is ready and starts running.

(5)

Task H starts running

(6)

At this time, task H wants to access the shared resource, so it needs to acquire the lock, but the lock is not released at this time, so task H blocks and waits for the mutex lock to be released.

(7)

Since L and H have the same priority at this time and are greater than M, task L continues to run.

(8)

Task L releases the mutex lock

(9)

Task H obtains the mutex lock resource, unblocks it and starts running. At this time, L’s priority returns to its original value.

(10)

Task H finishes running and enters blocking

(11)

Task M is now the highest priority in the ready list and starts running.

(12)

Task M finishes running and enters blocking

(13)

Task L starts a new round of running

3. API function of mutually exclusive semaphore

3.1, Create

SemaphoreHandle_t xSemaphoreCreateMutex(void)

  • Create a mutually exclusive semaphore

Parameters

Description

void

null

Return value

Description

NULL

Failed to create mutex semaphore

other values

Mutex semaphore created successfully

3.2, Release

Like the binary semaphore, please refer to the binary semaphore release function

3.3. Obtain

Like the binary semaphore, please refer to the binary semaphore release function

4. Experiment

4.1. Experimental design

The experimental design is the same as the process in the “Priority Flip” chapter, except that the “binary semaphore” is replaced by a “mutually exclusive semaphore”.

4.2, Experimental code

//Task 1
k_task_handle_t task1_handle; //Task 1 handle
#define TSK1_PRIO 2 //Task 1 priority
#define TASK1_STK_SIZE (1*512) //Stack size allocated by task 1

//Task 2
k_task_handle_t task2_handle; //Task 2 handle
#define TSK2_PRIO 3 //Task 2 priority
#define TASK2_STK_SIZE (1*512) //Stack size allocated by task 2

//Task 3
k_task_handle_t task3_handle; //Task 3 handle
#define TSK3_PRIO 4 //Task 3 priority
#define TASK3_STK_SIZE (1*512) //Stack size allocated by task 3


//Start task
k_task_handle_t start_task_handle; //Start task handle
#define START_TSK_PRIO 1 //Start task priority
#define START_TSK_STK_SIZE 1024 //Start task allocated stack size


#define TEST_TIME_QUANTA 100
k_mutex_handle_t g_Mutex; //mutex


void task1(void)
{
    uint32_t i = 0;
    while(1)
    {
            csi_kernel_mutex_lock(g_Mutex,portMAX_DELAY);
            my_printf("Low task running!\r\
");
            for(i=0;i<2000000;i + + )
            {
              taskYIELD();
            }
            csi_kernel_mutex_unlock(g_Mutex);
            csi_kernel_delay_ms(1000);
    }
}


void task2(void)
{
    while(1)
    {
            my_printf("Middle task running!\r\
");
            csi_kernel_delay_ms(1000);
    }
}

void task3(void)
{
    while(1)
    {
            csi_kernel_delay_ms(500);
            my_printf("High task Pend Semaphore\r\
");
            csi_kernel_mutex_lock(g_Mutex, portMAX_DELAY);
            my_printf("High task running!\r\
");
            csi_kernel_mutex_unlock(g_Mutex);
            csi_kernel_delay_ms(500);
    }
}



void start_task(void)
{
     //Enter the critical section
    taskENTER_CRITICAL();
    
     //Create mutex
    g_Mutex = csi_kernel_mutex_new();
    if(g_Mutex == NULL)
    {
        printf("fail to create mutex.\
");
    }

    //Create task 1
    csi_kernel_task_new((k_task_entry_t)task1, "task1", NULL, TSK1_PRIO, TEST_TIME_QUANTA, NULL, TASK1_STK_SIZE, & amp;task1_handle);
    if (task1_handle == NULL)
    {
        csi_kernel_sched_resume(0);
        my_printf("Fail to create task 1!\r\
");
    }

    //Create task 2
    csi_kernel_task_new((k_task_entry_t)task2, "task2", NULL, TSK2_PRIO, TEST_TIME_QUANTA, NULL, TASK2_STK_SIZE, & amp;task2_handle);
    if (task2_handle == NULL)
    {
        csi_kernel_sched_resume(0);
        my_printf("Fail to create task 2!\r\
");
    }
         
    //Create task 3
    csi_kernel_task_new((k_task_entry_t)task3, "task3", NULL, TSK3_PRIO, TEST_TIME_QUANTA, NULL, TASK3_STK_SIZE, & amp;task3_handle);
    if (task3_handle == NULL)
    {
        csi_kernel_sched_resume(0);
        my_printf("Fail to create task 3!\r\
");
    }
      

    //Delete the start task
    if(0 != csi_kernel_task_del(csi_kernel_task_get_cur()))
    {
            my_printf("Fail to delete start_task!\r\
");
    }
    else
    {
            my_printf("start_task is deleted!\r\
");
    }

    
    //Exit critical section
    taskEXIT_CRITICAL();
}



void freertos_demo(void)
{

    my_printf("\r\
-->this is freertos task test demo!!!\r\
"); //print message
   
    //system initialization
    csi_kernel_init();

        //Create a start task
    csi_kernel_task_new((k_task_entry_t)start_task, "start_task", 0, START_TSK_PRIO, 0, 0, START_TSK_STK_SIZE, & amp;start_task_handle);

        //Task scheduling starts
    csi_kernel_start();
        
}

4.3. Experimental phenomena

  • Task 3 (High task) will soon get a chance to run and will not be delayed for a long time by Task 2 (Middle task).