1.使用互斥信号量解决信号量导致的优先级反转,
2.使用递归互斥信号量解决互斥信号量导致的死锁。
3.高优先级主函数中多次使用同一信号量的使用,使用递归互斥信号量,但要注意每个信号量的使用要对应一个释放
优先级翻转问题
优先级翻转功能需求
优先级翻转功能实现
一。实验:优先级翻转问题
1.优先级翻转的解释
(1)有三个任务,一个任务L优先级最低,一个任务M优先级为中间,一个任务H优先级为最高。
(2)刚开始任务L在运行,并且L占用信号量
(3)H任务突然开始运行,抢占L任务,但是由于信号量由L占有,所以进入堵塞状态,CPU继续运行L任务。
(4)M任务突然开始运行,抢占M任务,M任务不需要信号量,所以需要等运行完毕CPU才会分配给L。
(5)L不需要占用临界资源后,释放信号量。H任务由堵塞态变为就绪态,抢占L,运行H。
2.功能需求
- 新建三个任务,优先级分别为中高低
- 新建二值信号量,用于模拟优先级翻转
- 低优先级任务获取信号量后,被中优先级打断,中优先级任务执行时间较长,因为低优先级任务还未释放信号量,高优先级任务就无法获取信号量继续
实现方法:
1.低优先级
(1)获取二值信号量(2)循环释放CPU使用权(3)释放二值信号量(4)系统延时500ms
2.高优先级业务流程
(1)获取二值信号量(2)释放二值信号量(3)系统延迟500ms
API:taskYIELD
3.cubemx创建工程
(1)创建一个高优先级的任务
(2)建一个二值信号量
3.步骤:
(1)低优先级
使用二值信号量,与高优先级使用的二值信号量是同一个。与高优先级相比,多了一个释放CPU权限的函数(taskYIELD())。
printf("Low Task Take sem\n");
//二值信号量的使用
if(xSemaphoreTake(PrBinarySemHandle,portMAX_DELAY)==pdPASS){
printf("Low Task is Running\n");
}
for(i=0;i<2000000;i++){
//释放cpu
taskYIELD();
}
//二值信号量的释放
printf("Low Task Give Sem\n");
xSemaphoreGive(PrBinarySemHandle);
osDelay(500);
(2)中优先级
不做特殊处理,就是直接打印
(3)高优先级
与低优先级一起使用一个二值信号量
printf("High Task Take sem\n");
if(xSemaphoreTake(PrBinarySemHandle,portMAX_DELAY)==pdPASS){
printf("High Task is running\n");
}
xSemaphoreGive(PrBinarySemHandle);
printf("High Task Give Sem\n");
osDelay(500);
结果:
二。互斥信号量概念及其应用《解决上述出现的问题:优先级反转问题》
互斥信号量定义
FreeRTOS互斥信号量介绍
FreeRTOS互斥信号量工作原理
1.互斥信号量的定义
短暂提升低优先级的优先级,让他优先完成。
任务都有一个互斥锁
2.FreeRTOS互斥信号量介绍
Mutex包括Mutex与RecursiveMutex(递归信号量解决普通信号量的死锁问题)
3.FreeRTOS互斥信号量工作原理
短暂提升低优先级的优先级,让他优先完成。
3.递归互斥信号量解决死锁问题
多次使用foo()函数会导致死锁,信号量重复使用,任务把自己挂起。
解决方法:递归互斥信号量
三。实验:互斥信号量函数应用
1.功能需求
1、修改优先级翻转实验(优化代码)
2、使用互斥信号量,解决优先级翻转问题
2.API
(1)xSemaphoreCreateMutex()创建互斥信号量
(2)xSemaphoreGetMutexHolder()获取当前信号量任务句柄
3.cubemx创建工程
(1)使能互斥信号量
(2)创建互斥信号量
3.步骤:
把优先级反转的二值信号量,改为互斥信号量,就可以解决优先级反转的问题
替代地方:
(1)低优先级信号量使用与释放处
(2)高优先级信号量使用与释放处
(1)低优先级二值信号量句柄的使用与释放修改为互斥信号量的使用与释放。
修改为
(2)高优先级一样
结果:大量时间用来运行高优先级的任务,正确。
四。实验:递归互斥信号量函数应用
1.死锁现象
上述的互斥信号量如果在同一个任务的主函数中运行两次互斥信号量的使用,会导致任务把自身挂起,即:死锁。
为了解决死锁的问题,使用递归互斥信号量。
2.API
(1)xSemaphoreCreateRecursiveMutex()
(2) xSemaphoreTakeRecursive()
(3)xSemaphoreGiveRecursive()
3.实验验证
需求:
1、模拟死锁现象
2、使用递归互斥信号量解决死锁问题
4.cubemx创建工程
(1)递归互斥信号量的使能
(2)创建递归互斥信号量
5.步骤
1.使用上述的API接口,创建与释放的递归信号量接口(FREERTOS的参考手册有详细讲解函数的使用,不过是英文)
2.使用自己创建的递归信号量
(1)创建出来的递归互斥信号量
(2)高优先级:如果直接使用互斥信号量,这样使用两次会导致死锁,使用递归互斥信号量就会解决此类问题。
//递归互斥信号量改为自己设置的信号量
printf("High Task Take sem1\n");
if(xSemaphoreTakeRecursive(myRecursiveMutexHandle,portMAX_DELAY)==pdPASS){
printf("High Task is running1\n");
}
printf("High Task Take sem2\n");
if(xSemaphoreTakeRecursive(myRecursiveMutexHandle,portMAX_DELAY)==pdPASS){
printf("High Task is running2\n");
}
xSemaphoreGiveRecursive(myRecursiveMutexHandle);
printf("High Task Give Sem1\n");
xSemaphoreGiveRecursive(myRecursiveMutexHandle);
printf("High Task Give Sem2\n");
osDelay(500);
(3)低优先级,注意:使用与高优先级一样的信号量
结果:高优先级占用CPU比率大,正确
五。互斥信号量实现原理