> 技术文档 > FreeRTOS—优先级翻转问题

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);}}

下图是运行的结果图:

FreeRTOS—优先级翻转问题

根据上图分析,二值信号量创建成功并释放了一个资源之后,自然高优先级任务就优先获取该信号量,运行结束并释放信号量之后,就到中等优先级任务运行了,中等优先级任务运行不受信号量控制,因此中等优先级任务运行按 1 秒的节奏运行,最后到低优先级任务获取信号量,但是该任务需要运行 5 秒,才能释放信号量给高优先级运行,这 5 秒之内,中等优先级任务也就运行了 5 次,因此就出现了优先级翻转。
为什么低优先级任务里面用了delay_ms(5000)函数,CPU会跑去运行中等优先级任务呢?

  • 这是因为被 SysTick 中断打断,导致调度器仍能切换任务,该函数里面操作的也是 SysTick 的寄存器