[FreeRTOS learning - mutex learning (stealing lock)]

Follow the learning records of Wei Dongshan's FreeRTOS teaching materials

FreeRTOS all project code links (updating)

https://gitee.com/chenshao777/free-rtos_-study


Understand the usage scenarios of mutexes

For example, when multiple tasks operate on the same array or variable , conflicts often occur. Task A may be interrupted by task B while accessing the arr array . Task B happens to also operate on the arr array. When task A continues to execute At this time, the arr array at this time is no longer the arr array at that time , which causes an access violation.

That is, non-atomic access, that is, the process of operation may be interrupted

To avoid this problem, you can lock the variable before accessing it, and unlock it after accessing it

  • That is, A locks before using the variable
  • A unlock after use
  • During this period, B must wait for A to unlock before using the variable, so that there will be no access conflict
  • But in fact, the code of FreeRTOS does not realize that who owns the lock can only be opened by who
  • So after A is locked, B can actually unlock it by himself.
  • Therefore, whoever locks and who can unlock the lock needs to be agreed by the programmer.
  • This lock is what we call a mutex, and a mutex is a special binary semaphore.

To use a mutex, it needs to be defined in the configuration file FreeRTOSConfig.h:

#define   configUSE_MUTEXES   1

1. Create a mutex

Second, the operation function of the mutex (acquire, release, delete)

3. Example of mutex usage

4. Lock theft


1. Create a mutex

QueueHandle_t xSemaphoreMutex;  //互斥量句柄

/* 创建互斥量,返回它的句柄 */
xSemaphoreMutex = xSemaphoreCreateMutex();

Second, the operation function of the mutex (acquire, release, delete)

/*
 * xSemaphore: 信号量句柄,你要删除哪个信号量, 互斥量也是一种信号量
 */
void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );

/* 释放 */
BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );

/* 释放(ISR版本) */
BaseType_t xSemaphoreGiveFromISR(
                       SemaphoreHandle_t xSemaphore,
                       BaseType_t *pxHigherPriorityTaskWoken
                   );

/* 获取 */
BaseType_t xSemaphoreTake(
                   SemaphoreHandle_t xSemaphore,
                   TickType_t xTicksToWait
               );
/* 获取 (ISR版本) */
xSemaphoreGiveFromISR(
                       SemaphoreHandle_t xSemaphore,
                       BaseType_t *pxHigherPriorityTaskWoken
                   );


3. Example of mutex usage

Create two tasks

  • Task 1 keeps sending numbers from 0 to 99
  • Task 2 has been sending 100~199 numbers

1. When the mutex is not used (USE_Mutex_Flag is set to 0)

As a result of the experiment, the sent data is mixed together:

insert image description here
2. The case of using a mutex (USE_Mutex_Flag is set to 1)

As a result of the experiment, sending data does not cause confusion:

insert image description here
code show as below:

void systemInit(void);   //各模块初始化

QueueHandle_t xSemaphoreMutex;  //互斥量句柄

void systemInit(void);   //各模块初始化

QueueHandle_t xSemaphoreMutex;  //互斥量句柄

/* 使用互斥量标志 */
#define     USE_Mutex_Flag 	   0   

/*
 * 任务1一直发送0~99数字
*/
void vSemphrMutex_Task1(void *pvParameters)
{
    
    
	const TickType_t xDelay = 50 / portTICK_PERIOD_MS;
	
	BaseType_t result;
	
	for(;;)
	{
    
    
		#if (USE_Mutex_Flag == 1)
			/* 上锁 */
			xSemaphoreTake(xSemaphoreMutex, portMAX_DELAY);
		#endif
		
		/* 打印 0 ~ 99 */
		for(int i=0; i < 100 ; i++){
    
    
			printf("%d ", i);
		}
		printf("\r\n");
		
		#if (USE_Mutex_Flag == 1)
			/* 开锁 */
			xSemaphoreGive(xSemaphoreMutex);
		#endif
		
		vTaskDelay(xDelay);
	}
}

/*
 * 任务2一直发送100~199数字
*/
void vSemphrMutex_Task2(void *pvParameters)
{
    
    
	const TickType_t xDelay = 50 / portTICK_PERIOD_MS;
	
	BaseType_t result;  //获取信号量结果变量
	
	for(;;)
	{
    
    
		#if (USE_Mutex_Flag == 1)
			/* 上锁 */
			xSemaphoreTake(xSemaphoreMutex, portMAX_DELAY);
		#endif
		
		/* 打印 100 ~ 199 */
		for(int i=100; i < 200 ; i++){
    
    
			printf("%d ", i);
		}
		printf("\r\n");
		
		#if (USE_Mutex_Flag == 1)
			/* 开锁 */
			xSemaphoreGive(xSemaphoreMutex);
		#endif
		
		vTaskDelay(xDelay);
	}
}

int main()
{
    
    
	systemInit();   //初始化各个模块

	// 互斥量任务一
	xTaskCreate(vSemphrMutex_Task1, "vSemphrMutex_Task1", 200, NULL, 2, NULL);
	
	// 互斥量任务二
	xTaskCreate(vSemphrMutex_Task2, "vSemphrMutex_Task2", 200, NULL, 2, NULL);
	
	vTaskStartScheduler();          //开启任务调度
}

/*
 * 初始化各个模块
*/
void systemInit(void)
{
    
    
	SysTick_Init(72);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
	USART1_Init(115200);
	printf("串口初始化成功!\r\n");

	/* 创建互斥量 */
	xSemaphoreMutex = xSemaphoreCreateMutex();
}

4. Lock theft

  • After task 2 is locked, start printing

  • Task 1 to lock (Take), find failure, do not wait

  • Task 1 directly unlocks the lock (Give), referred to as stealing the lock (because it was originally agreed that whoever locks the lock can only be opened by whoever)

  • Task 1 unlock (Give) is successful, start printing

  • Since the priority is the same, tasks 1 and 2 print alternately

  1. Task 1 theft lock code is as follows:

insert image description here

  1. Stealing results:

insert image description here

Guess you like

Origin blog.csdn.net/HuangChen666/article/details/129999772