本文主要是介绍【FreeRTOS】信号量实验-优先级反转,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
目录
- 0 前言
- 0 引言
- 2 问题复现
- 2.1 Car1Task
- 2.2 Car2Task
- 2.3 Car3Task
- 4. 互斥量_领导临时提拔你(解决优先级反转)
0 前言
学习视频:
【FreeRTOS入门与工程实践 --由浅入深带你学习FreeRTOS(FreeRTOS教程 基于STM32,以实际项目为导向)】 【精准空降到 03:06】 https://www.bilibili.com/video/BV1Jw411i7Fz/?p=41&share_source=copy_web&vd_source=8af85e60c2df9af1f0fd23935753a933&t=186
参考《FreeRTOS入门与工程实践(基于DshanMCU-103).pdf》
0 引言
在使用信号量的时候,不论是计数型信号量,还是二进制信号量,都可能会遇到优先级反转的问题。
- 优先级不反转:高优先级的任务先运行,低优先级的任务后运行。
- 低优先级任务先运行,高优先级的任务反而不能运行!
什么时候出现这种情况呢?
假设
- 最低优先级的任务先Take,先获得了信号量
- 中优先级的任务创建出来了,优先级比较高,会一直运行(任务2不去获得信号量)
- 最高优先级的任务最后创建,也想获得信号量,但是失败;假设信号量是1,这里就获取不到信号量了
在这个场景里面,任务3的优先级比任务2的优先级要高,但是任务3被任务2阻塞了,这样就是优先级反转!
2 问题复现
我们现在复现这个问题,第二个任务优先级设置为中等,但是他不去获得信号量,会阻塞第一个任务。导致第一个任务没有办法运行,第一个任务没有办法释放信号量,第三个任务就没有机会运行了
本节源码:在"20_semaphore_binary"的基础上,改出:21_semaphore_priority_inversion,演示优先级反转。
现在没有创建第 21 个程序
依次提高一个优先级,在game2.c的最后面修改代码
xTaskCreate(Car1Task, "car1", 128, &g_cars[0], osPriorityNormal+1, NULL);xTaskCreate(Car2Task, "car2", 128, &g_cars[1], osPriorityNormal+2, NULL);xTaskCreate(Car3Task, "car3", 128, &g_cars[2], osPriorityNormal+3, NULL);
2.1 Car1Task
static void Car1Task(void *params)
{struct car *pcar = params;struct ir_data idata;/* 创建自己的队列 */QueueHandle_t xQueueIR = xQueueCreate(10, sizeof(struct ir_data));/* 注册队列 */RegisterQueueHandle(xQueueIR);/* 显示汽车 */ShowCar(pcar);/* 先获取信号量 */xSemaphoreTake(g_xSemTicks, portMAX_DELAY); //不成功就永远等待while (1){/* 读取按键值:读队列 */// xQueueReceive(xQueueIR, &idata, portMAX_DELAY);/* 控制汽车往右移动 */// if (idata.val == pcar->control_key){if (pcar->x < g_xres - CAR_LENGTH){/* 隐藏汽车 */HideCar(pcar);/* 调整位置 */pcar->x += 2;if (pcar->x > g_xres - CAR_LENGTH){pcar->x = g_xres - CAR_LENGTH;}/* 重新显示汽车 */ShowCar(pcar);vTaskDelay(50);if (pcar->x == g_xres - CAR_LENGTH) //移动到最右边{/* 释放信号量 */xSemaphoreGive(g_xSemTicks);vTaskDelete(NULL);}}}}
}
2.2 Car2Task
- 复制第一个任务的函数
- 第二个任务不去获得信号量,但是要延迟一会~
- 运行到最右边也不释放信号量
static void Car2Task(void *params)
{struct car *pcar = params;struct ir_data idata;/* 创建自己的队列 */QueueHandle_t xQueueIR = xQueueCreate(10, sizeof(struct ir_data));/* 注册队列 */RegisterQueueHandle(xQueueIR);/* 显示汽车 */ShowCar(pcar);vTaskDelay(1000); //1S后运行// /* 先获取信号量 */
// xSemaphoreTake(g_xSemTicks, portMAX_DELAY); //不成功就永远等待while (1){/* 读取按键值:读队列 */// xQueueReceive(xQueueIR, &idata, portMAX_DELAY);/* 控制汽车往右移动 */// if (idata.val == pcar->control_key){if (pcar->x < g_xres - CAR_LENGTH){/* 隐藏汽车 */HideCar(pcar);/* 调整位置 */pcar->x += 2;if (pcar->x > g_xres - CAR_LENGTH){pcar->x = g_xres - CAR_LENGTH;}/* 重新显示汽车 */ShowCar(pcar);// vTaskDelay(50);mdelay(50); //阻塞等待if (pcar->x == g_xres - CAR_LENGTH) //移动到最右边{/* 释放信号量 *///xSemaphoreGive(g_xSemTicks);vTaskDelete(NULL);}}}}
}
2.3 Car3Task
任务3的优先级最高,我们修改一下delay,让他最后启动
static void Car3Task(void *params)
{struct car *pcar = params;struct ir_data idata;/* 创建自己的队列 */QueueHandle_t xQueueIR = xQueueCreate(10, sizeof(struct ir_data));/* 注册队列 */RegisterQueueHandle(xQueueIR);/* 显示汽车 */ShowCar(pcar);vTaskDelay(2000); // 2S后运行/* 先获取信号量 */xSemaphoreTake(g_xSemTicks, portMAX_DELAY); //不成功就永远等待while (1){/* 读取按键值:读队列 */// xQueueReceive(xQueueIR, &idata, portMAX_DELAY);/* 控制汽车往右移动 */// if (idata.val == pcar->control_key){if (pcar->x < g_xres - CAR_LENGTH){/* 隐藏汽车 */HideCar(pcar);/* 调整位置 */pcar->x += 2;if (pcar->x > g_xres - CAR_LENGTH){pcar->x = g_xres - CAR_LENGTH;}/* 重新显示汽车 */ShowCar(pcar);// vTaskDelay(50);mdelay(50); //阻塞等待if (pcar->x == g_xres - CAR_LENGTH) //移动到最右边{/* 释放信号量 */xSemaphoreGive(g_xSemTicks);vTaskDelete(NULL);}}}}
}
写完这三个任务之后,烧录运行,现象是第一辆车先跑1秒,然后停住,第二辆车跑到终点,之后第一辆车在停止的位置继续前进,第一辆车行驶到终点之后,第三辆车才行驶,到终点停止。
韦老师举了一个日常生活的例子
假设学校机房里有且仅有一台超算,一名学生为了学习,早早来到实验室机房学习了,并且按下指纹进行身份验证,日上三竿,主任带着领导来参观了,主任说你这个太吵了,先停下,超算不许使用了,最后校长来了,校长也是个科研工作者,校长也想使用超算,但是超算已经被学生按下了指纹,抢占了使用权限,没办法校长只能等待,这里就被主任卡住了,校长就非常恼火,这样就是优先级反转的例子。
4. 互斥量_领导临时提拔你(解决优先级反转)
本节源码:在"21_semaphore_priority_inversion"的基础上,改出:22_mutex_priority_inversion
这篇关于【FreeRTOS】信号量实验-优先级反转的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!