FreeRTOS—优先级翻转问题
文章目录
- 一、优先级翻转简介
- 二、实验
- 2.1.实验设计
- 2.2.软件设计
一、优先级翻转简介
优先级翻转顾名思义就是:高优先级的任务变成最后执行,低优先级的任务反而优先执行。优先级翻转在抢占式内核中是很常见的问题,但是在实时操作系统中是不允许出现优先级翻转的,因为优先级翻转会破环任务的预期顺序,可能会导致未知的严重后果。在使用二值信号量的时候,经常会遇到优先级翻转问题。
二、实验
2.1.实验设计
本实验设计四个任务:
- start_task:创建其他任务
- high_task:高优先级任务,会获取二值信号量,获取成功以后打印提示信息,处理完后释放信号量
- middle_task:中等优先级任务,简单的应用任务
- low_task:低优先级任务,和高优先级任务操作一致,不同的是低优先级任务占用信号量的时间久一点
2.2.软件设计
在入口函数里面创建二值信号量,并释放一个资源给下面两个任务:
void freertos_demo(void)
{semphr_handle = xSemaphoreCreateBinary();if(semphr_handle != NULL){printf("二值信号量创建成功\r\n");}xSemaphoreGive(semphr_handle);xTaskCreate((TaskFunction_t) start_task,(char*) "start_task",(uint16_t) START_TASK_STACK_SIZE,(void*) NULL,(UBaseType_t) START_TASK_PRIO,(TaskHandle_t*) &start_task_handler);vTaskStartScheduler();
}
下面是三个不同优先级的任务,high_task 函数优先级最高,依次递减:
void low_task(void *pvParameters)
{while(1){xSemaphoreTake(semphr_handle, portMAX_DELAY); printf("低优先级任务获取信号量成功\r\n");printf("低优先级任务正在运行\r\n");delay_ms(5000);printf("低优先级任务释放信号量\r\n");xSemaphoreGive(semphr_handle);vTaskDelay(1000);}
}void middle_task(void *pvParameters)
{uint8_t i = 0;while(1){printf("中等任务运行:%d\r\n",++i);vTaskDelay(1000);}
}void high_task(void *pvParameters)
{while(1){xSemaphoreTake(semphr_handle, portMAX_DELAY);printf("高优先级任务获取信号量成功\r\n");printf("高优先级任务正在运行\r\n");delay_ms(1000);printf("高优先级任务释放信号量\r\n");xSemaphoreGive(semphr_handle);vTaskDelay(1000);}
}
下图是运行的结果图:
根据上图分析,二值信号量创建成功并释放了一个资源之后,自然高优先级任务就优先获取该信号量,运行结束并释放信号量之后,就到中等优先级任务运行了,中等优先级任务运行不受信号量控制,因此中等优先级任务运行按 1 秒的节奏运行,最后到低优先级任务获取信号量,但是该任务需要运行 5 秒,才能释放信号量给高优先级运行,这 5 秒之内,中等优先级任务也就运行了 5 次,因此就出现了优先级翻转。
为什么低优先级任务里面用了delay_ms(5000)
函数,CPU会跑去运行中等优先级任务呢?
- 这是因为被 SysTick 中断打断,导致调度器仍能切换任务,该函数里面操作的也是 SysTick 的寄存器