|
使用信号量的任务是否能够运行是受到任务的优先级别以及是否占用信号量两个条件约束的,而信号量的约束高于优先级别的约束。 于是,当出现地优先级别的任务与高优先级别的任务使用同一个信号量时,而系统中还存在其他中等优先级的任务时,如果低优先级的任务获得了信号量,就会使高优先级的任务处于等待状态;而那些不适用该信号量的中等优先级别的任务却可以剥夺低优先级别的任务的 CPU 使用权,而先于高优先级别的任务运行。
---------------------------------------------------------------------------------------------------------------------------------------------
解决问题的办法之一是:使获得信号量任务的优先级别在使用共享资源期间暂时提升到所有任务最高优先级的搞一个级别上,已使该任务不被其它任务打断,从而尽快地使用完共享资源并释放信号量;然后在释放信号量之后,再恢复该任务原来的优先级别。
使用互斥型信号量即是解决优先级反转的手段之一。
---------------------------------------------------------------------------------------------------------------------------------------------
如下代码会产生优先级的反转:#include "includes.h"
#define TASK_STK_SIZE 512
OS_STK StartTaskStk[TASK_STK_SIZE];
OS_STK MyTaskStk[TASK_STK_SIZE]; /* Tasks stacks */
OS_STK YouTaskStk[TASK_STK_SIZE];
OS_STK HerTaskStk[TASK_STK_SIZE];
INT16S key;
char *s1 = "MyTask is running";
char *s2 = "YouTask is running";
char *s3 = "HerTask is running";
char *ss = "Mytask require the semaphore";
INT8U err;
INT8U y = 0;
INT32U times = 0;
OS_EVENT *Semp;
void StartTask(void *data);
void MyTask(void *data); /* Function prototypes of Startup task */
void YouTask(void *data);
void HerTask(void *data);
void main (void)
{
PC_DispClrScr(DISP_FGND_WHITE + DISP_BGND_BLACK); /* Clear the screen */
OSInit(); /* Initialize uC/OS-II */
PC_DOSSaveReturn(); /* Save environment to return to DOS */
PC_VectSet(uCOS, OSCtxSw); /* Install uC/OS-II's context switch vector */
Semp = OSSemCreate(1);
OSTaskCreate(StartTask, (void *)0, &StartTaskStk[TASK_STK_SIZE - 1], 0);
OSStart(); /* Start multitasking */
}
void StartTask(void *pdata)
{
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr;
#endif
pdata = pdata; /* Prevent compiler warning */
OS_ENTER_CRITICAL();
PC_VectSet(0x08, OSTickISR); /* Install uC/OS-II's clock tick ISR */
PC_SetTickRate(OS_TICKS_PER_SEC); /* Reprogram tick rate */
OS_EXIT_CRITICAL();
OSStatInit(); /* Initialize uC/OS-II's statistics */
OSTaskCreate(MyTask,(void *)0, &MyTaskStk[TASK_STK_SIZE - 1], 3);
OSTaskCreate(YouTask,(void *)0, &YouTaskStk[TASK_STK_SIZE - 1], 4);
OSTaskCreate(HerTask,(void *)0, &HerTaskStk[TASK_STK_SIZE - 1], 5);
for(;;)
{
if( PC_GetKey(&key) == TRUE )
{
if( key == 0x1B )
{
PC_DOSReturn();
}
}
OSTimeDlyHMSM(0,0,3,0);
}
}
void MyTask (void *pdata)
{
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr;
#endif
pdata = pdata; /* Prevent compiler warning */
for (;;)
{
OSTimeDlyHMSM(0,0,0,200);
PC_DispStr(10,++y,ss,DISP_BGND_BLACK + DISP_FGND_WHITE);
OSSemPend(Semp,0,&err);
PC_DispStr(10,++y,s1,DISP_BGND_BLACK + DISP_FGND_WHITE);
OSSemPost(Semp);
OSTimeDlyHMSM(0,0,0,200);
}
}
void YouTask(void *pdata)
{
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr;
#endif
pdata = pdata;
for (;;)
{
PC_DispStr(10,++y,s2,DISP_BGND_BLACK + DISP_FGND_WHITE);
OSTimeDlyHMSM(0,0,0,300);
}
}
void HerTask( void *pdata )
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
pdata = pdata;
for(;;)
{
OSSemPend( Semp,0,&err);
PC_DispStr(10,++y,s3,DISP_BGND_BLACK + DISP_FGND_WHITE);
for( times; times<20000000; times++ )
{
OS_Sched();
}
OSSemPost( Semp );
OSTimeDlyHMSM(0,0,1,0);
}
}
---------------------------------------------------------------------------------------------------------------------------------------
把信号量改成了互斥型信号量后,可以修正优先级反转的问题。修改后,运行效果图:
由图可见,因为 MyTask 的优先级高于 HerTask,当 Mytask申请信号量时,HerTask的优先级被提升到PIP,以求尽快的释放信号量;而当 HerTask使用完并释放信号量后,就恢复为原来的优先级,此后 Mytask 得到信号量并开始运行。 |
|