今日通过实验展示一个优先级反转的现象:
本文学习与程序编写基于 正点原子的 STM32F1 UCOS开发手册
文章提供测试代码讲解、完整工程下载、测试效果图
本文就展示这样一个现象,程序工程没有意义,就不提供下载了,自己写写体验体验......
目录
优先级反转的原因:
目前各个文件任务:
优先级 ComTask >MessageTask > CalculateTask
#include "main.h"
#include "ComTask.h"
#include "MessageTask.h"
#include "CalculateTask.h"
测试结果截图:
优先级反转的原因:
我个人总结为:
高优先级的任务因为等待信号量被释放,一直处于挂起态,导致其任务优先级等效于降低了
优先级反转的后果
优先级反转是指在可剥夺内核中,当任务以独占方式使用共享资源时,出现低优先级任务先于高优先级任务运行的现象。这种现象破坏了任务执行的预期顺序,可能对实时系统造成严重后果:
- 延迟高优先级任务:高优先级任务可能因为等待低优先级任务释放信号量而被延迟执行。这可能导致系统响应时间变长,影响系统的实时性。
- 降低系统性能:优先级反转可能导致CPU资源浪费在等待任务上,而不是在执行实际的工作。这会降低系统的整体性能。
- 系统不稳定:如果优先级反转频繁发生,或者涉及的任务数量众多,可能会导致系统变得不稳定,甚至可能出现死锁或其他严重的系统问题。
实验展示优先级反转:
目前各个文件任务:
优先级 ComTask >MessageTask > CalculateTask
#include "main.h"
创建开始任务初始化每个基本任务、创建 SEM_Shared_Str 信号量:
#include "main.h"void start_task(void *p_arg);//开始任务函数int main(void) {OS_ERR err;CPU_SR_ALLOC();Init_ALL();OSInit(&err); //初始化UCOSIIIOS_CRITICAL_ENTER();//进入临界区//创建开始任务OSTaskCreate((OS_TCB * )&StartTaskTCB, //任务控制块(CPU_CHAR * )"start task", //任务名字(OS_TASK_PTR )start_task, //任务函数(void * )0, //传递给任务函数的参数(OS_PRIO )START_TASK_PRIO, //任务优先级(CPU_STK * )&START_TASK_STK[0], //任务堆栈基地址(CPU_STK_SIZE)START_STK_SIZE/10, //任务堆栈深度限位(CPU_STK_SIZE)START_STK_SIZE, //任务堆栈大小(OS_MSG_QTY )0, //任务内部消息队列能够接收的最大消息数目,为0时禁止接收消息(OS_TICK )0, //当使能时间片轮转时的时间片长度,为0时为默认长度,(void * )0, //用户补充的存储区(OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, //任务选项(OS_ERR * )&err); //存放该函数错误时的返回值OS_CRITICAL_EXIT(); //退出临界区 OSStart(&err); //开启UCOSIIIwhile(1); }//开始任务函数 void start_task(void *p_arg) {OS_ERR err;CPU_SR_ALLOC();p_arg = p_arg;CPU_Init(); #if OS_CFG_STAT_TASK_EN > 0uOSStatTaskCPUUsageInit(&err); //统计任务 #endif#ifdef CPU_CFG_INT_DIS_MEAS_EN //如果使能了测量中断关闭时间CPU_IntDisMeasMaxCurReset(); #endif#if OS_CFG_SCHED_ROUND_ROBIN_EN //当使用时间片轮转的时候//使能时间片轮转调度功能,时间片长度为1个系统时钟节拍,既1*5=5msOSSchedRoundRobinCfg(DEF_ENABLED,1,&err); #endif //初始化 OS_Timer1_Periodic 软件定时器OSTmrCreate((OS_TMR *) &OS_Timer1_Periodic , //OS系统 软件定时器 1 周期模式 (CPU_CHAR *) "OS_Timer1_Periodic", //定时器名称(OS_TICK ) 100, // 启动延时 为100*10 ms(OS_TICK ) 20, // 周期为 20*10 ms(OS_OPT ) OS_OPT_TMR_PERIODIC, //周期定时模式(OS_TMR_CALLBACK_PTR ) OS_Timer1_Periodic_callback,//回调函数(void * ) 0,//参数为0(OS_ERR *) &err );OS_CRITICAL_ENTER(); //进入临界区//创建ComTask任务OSTaskCreate((OS_TCB * )&COMTASKTaskTCB, (CPU_CHAR * )"com task", (OS_TASK_PTR )comTask, (void * )0, (OS_PRIO )COMTASK_TASK_PRIO, (CPU_STK * )&COMTASK_TASK_STK[0], (CPU_STK_SIZE)COMTASK_STK_SIZE/10, (CPU_STK_SIZE)COMTASK_STK_SIZE, (OS_MSG_QTY )0, (OS_TICK )0, //之前为0 //2个时间片 2*5ms(void * )0, (OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,(OS_ERR * )&err); //创建MessageTask任务OSTaskCreate((OS_TCB * )&MessageTaskTaskTCB, (CPU_CHAR * )"Message task", (OS_TASK_PTR )MessageTask, (void * )0, (OS_PRIO )MessageTask_TASK_PRIO, (CPU_STK * )&MessageTask_TASK_STK[0], (CPU_STK_SIZE)MessageTask_STK_SIZE/10, (CPU_STK_SIZE)MessageTask_STK_SIZE, (OS_MSG_QTY )0, (OS_TICK )0, //之前为0 //2个时间片 2*5ms(void * )0, (OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, (OS_ERR * )&err);//创建CalculateTask任务OSTaskCreate((OS_TCB * )&CalculateTaskTaskTCB, (CPU_CHAR * )"Calculate task", (OS_TASK_PTR )CalculateTask, (void * )0, (OS_PRIO )CalculateTask_TASK_PRIO, (CPU_STK * )&CalculateTask_TASK_STK[0], (CPU_STK_SIZE)CalculateTask_STK_SIZE/10, (CPU_STK_SIZE)CalculateTask_STK_SIZE, (OS_MSG_QTY )0, (OS_TICK )0, (void * )0, (OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, (OS_ERR * )&err); //创建 Shared_Str共享全局资源 的 信号量 OSSemCreate((OS_SEM *) &SEM_Shared_Str, //指向信号量(CPU_CHAR *) "SEM_Shared_Str", //信号量名称( OS_SEM_CTR ) 1, //信号量值为1(OS_ERR *) &err);OS_TaskSuspend((OS_TCB*)&StartTaskTCB,&err); //挂起开始任务 OS_CRITICAL_EXIT(); //进入临界区 }
#include "ComTask.h"
#include "ComTask.h"/*ComTask ComTask 计数打印自己运行次数请求发送信号量等待800ms */ void comTask(void * p_arg) {OS_ERR err;int i=0,OSTime_tickRate;//char ComTask_str[]="ComTask_write";p_arg = p_arg;OSTime_tickRate=OSCfg_TickRate_Hz; //获取系统节拍频率,(该宏定义在 OS_CFG_APP.H)UsartPrintf(USART1, "OSCfg_TickRate_Hz = %d Hz \r\n",OSTime_tickRate); //打印系统节拍频率while (DEF_TRUE){i++;UsartPrintf(USART1, "ComTask Pend SEM\r\n"); OSSemPend(&SEM_Shared_Str,0,OS_OPT_PEND_BLOCKING,0,&err);//请求信号量UsartPrintf(USART1, "ComTask Print %d\r\n",i); OSSemPost(&SEM_Shared_Str,OS_OPT_POST_1,&err); //发送信号量OSTimeDlyHMSM(0,0,0,800,OS_OPT_TIME_HMSM_STRICT,&err); //延时800ms} }
#include "MessageTask.h"
#include "MessageTask.h"/*MessageTask打印自己运行次数等待500ms' */ void MessageTask (void * p_arg) {OS_ERR err;int i=0;//char MessageTask_str[]="MessageTask_write";p_arg = p_arg;while (DEF_TRUE){i++;UsartPrintf(USART1, "MessageTask Print %d\r\n",i); //之前这里会卡系统,因为任务栈太小 MessageTask_STK_SIZE 128OSTimeDlyHMSM(0,0,0,500,OS_OPT_TIME_HMSM_STRICT,&err); //延时500ms}}
#include "CalculateTask.h"
#include "CalculateTask.h"/* CalculateTask 打印自己运行次数 请求信号量,发起任务调度,发送信号量 模拟长时间占用信号量然后等待1000ms */ void CalculateTask(void *p_arg) {OS_ERR err;int i=0;int times;p_arg = p_arg;while (DEF_TRUE){i++;OSSemPend(&SEM_Shared_Str,0,OS_OPT_PEND_BLOCKING,0,&err);//请求信号量UsartPrintf(USART1, "CalculateTask Print %d\r\n",i);for(times=0;times<20000000;times++){OSSched();//发起任务调度}OSSemPost(&SEM_Shared_Str,OS_OPT_POST_1,&err); //发送信号量OSTimeDlyHMSM(0,0,0,1000,OS_OPT_TIME_HMSM_STRICT,&err); //延时1000ms} }
测试结果截图:
我们发现,由于最低优先级的任务长时间占用信号量,导致最高优先级的反而一直没法运行,而中等优先级的可以正常运行