µC/OS-II 示例 ucos优先级反转现象

优先级反转发生在有多个任务需要使用共享资源的情况下,可能会出现高优先级任务被低优先级任务阻塞,并等待低优先级任务执行的现象。

高优先级任务需要等待低优先级任务释放资源,而低优先级任务又正在等待中等优先级任务,这种现象就被称为优先级反转。

两个任务都试图访问共享资源是出现优先级反转最通常的情况。为了保证一致性,这种访问应该是顺序进行的。如果高优先级任务首先访问共享资源,则会保持共享资源访问的合适的任务优先级顺序;

但如果是低优先级任务首先获得共享资源的访问,然后高优先级任务请求对共享资源的访问,则高优先级任务被阻塞,直到低优先级任务完成对共享资源的访问。

 

1)设计了3个应用任务TA0~TA2,其优先级逐渐降低,任务TA0的优先级最高。

2)除任务TA1外,其它应用任务都要使用同一种资源,该资源必须被互斥使用。为此,创建一个二值信号量mutex来模拟该资源。虽然μC/OS-Ⅱ在创建信号量时可以选择采用防止优先级反转的策略,但在本实验中我们不使用这种策略。

 

设计运行流程:

程序:

#include "includes.h"
#define  TASK_STK_SIZE 512      

void TaskStart(void *pdata);
void Task0(void *pdata);
void Task1(void *pdata);
void Task2(void *pdata);

OS_STK TaskStartStk[TASK_STK_SIZE]; 
OS_STK Task0Stk[TASK_STK_SIZE];        
OS_STK Task1Stk[TASK_STK_SIZE];
OS_STK Task2Stk[TASK_STK_SIZE];

INT16S key;
INT8U y=0;
INT8U err;
char*s;
OS_EVENT*Semp; 

void  main (void)
{
    OSInit();                                              
    PC_DOSSaveReturn();                                 
    PC_VectSet(uCOS, OSCtxSw);
    OSTaskCreate(TaskStart,(void*)0,&TaskStartStk[TASK_STK_SIZE - 1],0);    
    OSStart();                                           
}

void TaskStart(void *pdata)
{

#if OS_CRITICAL_METHOD == 3                               
    OS_CPU_SR  cpu_sr;
#endif
    pdata = pdata;                                        

    OS_ENTER_CRITICAL();
    PC_VectSet(0x08, OSTickISR);                          
    PC_SetTickRate(OS_TICKS_PER_SEC);                      
    OS_EXIT_CRITICAL();
    OSStatInit();                                          

    OSTaskCreate(Task0,0,&Task0Stk[TASK_STK_SIZE-1],1);
    OSTaskCreate(Task1,0,&Task1Stk[TASK_STK_SIZE-1],2);
    OSTaskCreate(Task2,0,&Task2Stk[TASK_STK_SIZE-1],3);  
    
    OSTaskSuspend(OS_PRIO_SELF);

   	for (;;) 
	{
        if(PC_GetKey(&key)==TRUE)
	  	{
            if(key==0x1B)
			{
		   		PC_DOSReturn();
			}
	  	}
    	OSTimeDlyHMSM(0,0,3,0);      
    }
}

void Task0(void *pdata)
{
#if OS_CRITICAL_METHOD==3
   	OS_CPU_SR cpu_sr;
#endif
    pdata=pdata;
    for(;;)
    {
    	OSTimeDlyHMSM(0,0,3,0);
    	s="Task0 start!";
    	PC_DispStr(15,++y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
    	
		OSTimeDlyHMSM(0,0,1,0);
    	OSSemPend(Semp,0,&err);
    	OSTimeDlyHMSM(0,0,2,0);
    	
    	s="Task0 completion!";
    	PC_DispStr(15,++y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
        OSSemPost(Semp);  
		      
       	OSTimeDlyHMSM(0,0,5,0);       
    }
}

void Task1(void *pdata)
{
#if OS_CRITICAL_METHOD==3
   	OS_CPU_SR cpu_sr;
#endif
    pdata=pdata;
    for(;;)
    {
    	OSTimeDlyHMSM(0,0,2,0);
    	s="Task1 start!";
    	PC_DispStr(15,++y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
    	
		OSTimeDlyHMSM(0,0,2,0);
    	
    	s="Task1 completion!";
    	PC_DispStr(15,++y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
		      
       	OSTimeDlyHMSM(0,0,5,0);       
    }
}

void Task2(void *pdata)
{
#if OS_CRITICAL_METHOD==3
   	OS_CPU_SR cpu_sr;
#endif
    pdata=pdata;
    for(;;)
    {
    	OSTimeDlyHMSM(0,0,1,0);
    	s="Task2 start!";
    	PC_DispStr(15,++y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
    	
    	OSSemPend(Semp,0,&err);
    	OSTimeDlyHMSM(0,0,2,0);
    	
    	s="Task2 completion!";
    	PC_DispStr(15,++y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
        OSSemPost(Semp);  
		      
       	OSTimeDlyHMSM(0,0,5,0);       
    }
}

结果:

TaskStart创建完Task0,Task1,Task2后挂起自己。

Task0优先级最大,Task2最小。

开始时Task0比Task2晚两秒运行。

Task1比Task2晚一秒运行。

Task2运行开始立刻获取共享资源Semp。

一秒后Task1因优先级高于Task2抢占CPU运行。

两秒后Task0因优先级高于Task1抢占CPU运行。

第三秒,Task0申请共享资源失败挂起。

剩余Task1优先级最高,运行直到结束。

之后Task2运行到结束,释放共享资源。

Task0获取资源后,最后运行结束。

 

因此,出现Task0为等待Task2释放共享资源,而被Task1这样低优先级无关进程抢占CPU运行的现象。

即为优先级翻转现象。

 

µC/OS-II相关函数

1 OSSemCreate()

该函数建立并初始化一个信号量,信号量的作用如下:

  1. 允许一个任务和其他任务或者中断同步
  2. 取得设备的使用权
  3. 标志事件的发生

函数原OSSemCreate( INT16U value);

参数说明:value 参数是所建立的信号量的初始值,可以取0到65535之间的任何值。

返回值:OSSemCreate()函数返回指向分配给所建立的信号量的控制块的指针。如果没有可用的控制块,OSSemCreate()函数返回空指针。

 

2 OSSemPend()

该函数用于任务试图取得设备的使用权、任务需要和其他任务或中断同步、任务需要等待特定事件的发生的场合。如果任务调用OSSemPend()函数时,信号量的值大于零,OSSemPend()函数递减该值并返回该值。如果调用时信号量值等于零,OSSemPend()函数将任务加入该信号量的等待队列。OSSemPend()函数挂起当前任务直到其他的任务或中断设置信号量或超出等待的预期时间。如果在预期的时钟节拍内信号量被设置,μC/OS-Ⅱ默认让最高优先级的任务取得信号量并回到就绪状态。一个被OSTaskSuspend()函数挂起的任务也可以接受信号量,但这个任务将一直保持挂起状态直到通过调用OSTaskResume()函数恢复该任务的运行。

函数原型:Void OSSemPend ( OS_EVNNT  *pevent, INT16U  timeout,  int8u *err );

参数说明:

pevent  是指向信号量的指针。该指针的值在建立该信号量时可以得到。(参考OSSemCreate()函数)。

Timeout  允许一个任务在经过了指定数目的时钟节拍后还没有得到需要的信号量时恢复就绪状态。如果该值为零表示任务将持续地等待信号量,最大的等待时间为65535个时钟节拍。这个时间长度并不是非常严格的,可能存在一个时钟节拍的误差。

Err 是指向包含错误码的变量的指针。

返回值:

OSSemPend()函数返回的错误码可能为下述几种:

  1. OS_NO_ERR :信号量不为零。
  2. OS_TIMEOUT :信号量没有在指定数目的时钟周期内被设置。
  3. OS_ERR_PEND_ISR :从中断调用该函数。虽然规定了不允许从中断调用该函数,但μC/OS-Ⅱ仍然包含了检测这种情况的功能。
  4. OS_ERR_EVENT_TYPE  :pevent 不是指向信号量的指针。

 

3 OSemPost()

该函数用于设置指定的信号量。如果指定的信号量是零或大于零,OSSemPost()函数递增该信号量的值并返回。如果有任何任务在等待该信号量,则最高优先级的任务将得到信号量并进入就绪状态。任务调度函数将进行任务调度,决定当前运行的任务是否仍然为最高优先级的就绪任务。

函数原:INT8U OSSemPost(OS_EVENT *pevent);

参数说明:pevent  是指向信号量的指针。该指针的值在建立该信号量时可以得到。(参考OSSemCreate()函数)。

返回值:

OSSemPost()函数的返回值为下述之一:

  1. OS_NO_ERR :信号量被成功地设置
  2. OS_SEM_OVF :信号量的值溢出
  3. OS_ERR_EVENT_TYPE  :pevent 不是指向信号量的指针

 

4 OSTimeDly()

该函数用于将一个任务延时若干个时钟节拍。如果延时时间大于0,系统将立即进行任务调度。延时时间的长度可从0到65535个时钟节拍。延时时间0表示不进行延时,函数将立即返回调用者。延时的具体时间依赖于系统每秒钟有多少个时钟节拍(由文件SO_CFG.H中的OS_TICKS_PER_SEC宏来设定)。

函数原型:void OSTimeDly ( INT16U ticks);

参数说明:ticks为要延时的时钟节拍数。

返回值:

 

 

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值