曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 7874|回复: 0
打印 上一主题 下一主题

实例:优先级反转

[复制链接]

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34387
跳转到指定楼层
楼主
发表于 2009-4-14 02:01:48 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
使用信号量的任务是否能够运行是受到任务的优先级别以及是否占用信号量两个条件约束的,而信号量的约束高于优先级别的约束。     于是,当出现地优先级别的任务与高优先级别的任务使用同一个信号量时,而系统中还存在其他中等优先级的任务时,如果低优先级的任务获得了信号量,就会使高优先级的任务处于等待状态;而那些不适用该信号量的中等优先级别的任务却可以剥夺低优先级别的任务的 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 得到信号量并开始运行。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2024-5-19 08:11 , Processed in 0.076680 second(s), 22 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表