一、什么是互斥量?
在多数情况下,互斥型信号量和二值型信号量非常相似,但是从功能上二值型信号量用于同步,而互斥型信号量用于资源保护。
互斥型信号量和二值型信号量还有一个最大的区别,互斥型信号量可以有效解决优先级反转现象。
二、什么是优先级翻转?
系统中有3个不同优先级的任务H/M/L,最高优先级任务H和最低优先级任务L通过信号量机制,共享资源。目前任务L占有资源,锁定了信号量,Task H运行后将被阻塞,直到Task L释放信号量后,Task H才能够退出阻塞状态继续运行。但是Task H在等待Task L释放信号量的过程中,中等优先级任务M抢占了任务L,从而延迟了信号量的释放时间,导致Task H阻塞了更长时间,这种现象称为优先级倒置或反转。
三、互斥量相关 API 函数
1.创建互斥量
SemaphoreHandle_t xSemaphoreCreateMutex( void );
参数:
无
返回值:
成功,返回对应互斥量的句柄;
失败,返回 NULL 。
2.释放互斥信号量
BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );
参数:
xSemaphore:要释放的信号量句柄
返回值:
成功,返回 pdPASS ;
失败,返回 errQUEUE_FULL 。
3.获取互斥信号量
BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore,
TickType_t xTicksToWait );
参数:
xSemaphore:要获取的信号量句柄
xTicksToWait:超时时间,0 表示不超时,portMAX_DELAY表示卡死等待;
返回值:
成功,返回 pdPASS ;失败,返回 errQUEUE_FULL 。
四、实操
•实验需求:
1. 演示优先级翻转
2. 使用互斥量优化优先级翻转问题
•cubeMX配置
•编程实现
void StartTaskH(void const * argument)
{
/* USER CODE BEGIN StartTaskH */
/* Infinite loop */
for(;;)
{
xSemaphoreTake(myMutexHandle,portMAX_DELAY);
printf("TaskH:我开始进入厕所,发功中...\r\n");
HAL_Delay(1000);
printf("TaskH:我上完厕所了,真舒服...\r\n");
xSemaphoreGive(myMutexHandle);
osDelay(1000);
}
/* USER CODE END StartTaskH */
}
void StartTaskM(void const * argument)
{
/* USER CODE BEGIN StartTaskM */
/* Infinite loop */
for(;;)
{
printf("TaskM:我就是为了占有CPU资源,带女朋友去兜风\r\n");
osDelay(1000);
}
/* USER CODE END StartTaskM */
}
void StartTaskL(void const * argument)
{
/* USER CODE BEGIN StartTaskL */
/* Infinite loop */
for(;;)
{
xSemaphoreTake(myMutexHandle,portMAX_DELAY);
printf("TaskL:我开始进入厕所,发功中...\r\n");
HAL_Delay(3000);
printf("TaskL:我上完厕所了,真舒服...\r\n");
xSemaphoreGive(myMutexHandle);
osDelay(1000);
}
/* USER CODE END StartTaskL */
}