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:
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:
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
- Task 1 theft lock code is as follows:
- Stealing results: