uC/OS-II任务调度中判断最高优先级

一、任务优先级的表示

   uC/OS-II中,规定最多可以有64个任务。每个任务的优先级不能相同,因此,优先级为0~63.数字越小,优先级越高,那么0就是最高优先级,63就是最低优先级。系统保留了优先级最高及最低的各4个,因此用户不能使用这8个优先级作为自己的任务的优先级。宏OS_LOWEST_PRIO用于设置规定最低优先级,如定义为30,那么比30数字大的更低优先级就不能用了。这里有点拗口。也就是,所有的任务不能多于31个。

  系统将64个优先级分为8组,每组8个。OSRdyGrp 表示组, OSRdytbl[]表示每一组。他们定义如下:

#if OS_LOWEST_PRIO <= 63
OS_EXT  INT8U   OSRdyGrp;      /* Ready list group     */
OS_EXT  INT8U   OSRdyTbl[OS_RDY_TBL_SIZE];  /* Table of tasks which are ready to run    */
#else
OS_EXT  INT16U  OSRdyGrp;    /* Ready list group   */
OS_EXT  INT16U  OSRdyTbl[OS_RDY_TBL_SIZE];       /* Table of tasks which are ready to run    */
#endif    

#if OS_LOWEST_PRIO <= 63
....
#define    OS_RDY_TBL_SIZE  ( ( OS_LOWEST_PRIO ) / 8 + 1 )          /* Size of ready table  */
#else
......
#define   OS_RDY_TBL_SIZE   ((OS_LOWEST_PRIO) / 16 + 1)           /* Size of ready table */
#endif
       这里好像是做了扩展,不局限于 8 位,貌似最多的任务不只 64 了。不管它,我们忽略另一种情况。因为不管多少任务,处理方式的是一样的。我们考虑所有优先级都有可能用到的情况, OS_LOWEST_PRIO 就应该定义为 63 OS_RDY_TBL_SIZE 就是。 OSRdyTbl 就是一个含 8 个元素的数组。

       好了,OSRdyGrp的每一位表示一个组,如果该位为1,表示有任务用到了该组内的优先级(由于优先级不能相同,也表明有该任务,否则没有)。OSRdyTbl[x]的每一位表示该组内的每一个优先级,为1就有。例如OSRdyGrp[bit : 2] = 1;第三组内存在一个任务,也即是优先级16~238个优先级存在一个及多个。如果此时OSRdyTbl[2][bit :4] = 1; 表示第三组的第5个优先级存在,也就是数值为20的优先级存在。

二、设置OSRdyGrpOSRdyTbl

        讲了优先级列表如何表示,那么接下来就是创建一个任务时,如何将其对应的优先级加入到列表中。这是OS_TCBInit函数的关于设置OSRdyGrpOSRdyTbl的代码。注:以下源码,就不摘录16位的情况。 

     ptcb->OSTCBY    =  (INT8U)(prio >> 3);         /* Pre-compute X, Y, BitX and BitY   */
     ptcb->OSTCBBitY      = (INT8U)(1 << ptcb->OSTCBY);
     ptcb->OSTCBX         = (INT8U)(prio & 0x07);
     ptcb->OSTCBBitX      = (INT8U)(1 << ptcb->OSTCBX);
     .........

      OSRdyGrp  |= ptcb->OSTCBBitY;         /* Make task ready to run    */
      OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
      优先级prio是传人的参数,由于不会大于 64 prio 6 位值,因此 OSTCBY prio 3 位,表示组,不会大于 8 OSTCBX prio 3 , 表示一个组的偏移量。OSRdyGrp OSRdyTbl 是按位表示的,就得将数值转化为位模式。接上面的例子 prio = 20 = 0x10100 OSTCBY是prio 高3 位,为 1 , 表明该优先级落在第二组(从 0 开始), OSTCBBitY=0x10 ,也就是 bit:1 1 。同理,OSTCBX= 4 OSTCBBitX  bit :5 1 OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;  就是设置 OSRdyTbl[1] bit5.

三、任务调度中判断最高优先级

        uC/OS-II每次任务调度都是运行最高优先级的任务。那么如何在所有的任务中寻找最高优先级了?前面已经介绍了,优先级信息存在OSRdyGrpOSRdyTbl中。低位代表高优先级。先检查组,由低位到高位检查,检查到后,再在该组中由低位到高位检查,第一个为1的就是最高优先级了。

       这个过程,说白了就是检查一个char型的数,所有位是1的最小的那个位。uC/OS-II中用的查表法进行的。表如下:

INT8U const OSUnMapTbl[256] = {
   0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x00 to 0x0F */
   4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x10 to 0x1F */
   5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x20 to 0x2F */
   4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x30 to 0x3F */
   6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x40 to 0x4F */
   4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x50 to 0x5F */
   5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x60 to 0x6F */
   4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x70 to 0x7F */
   7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x80 to 0x8F */
   4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x90 to 0x9F */
   5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0xA0 to 0xAF */
   4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0xB0 to 0xBF */
   6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0xC0 to 0xCF */
   4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0xD0 to 0xDF */
   5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0xE0 to 0xEF */
   4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 /* 0xF0 to 0xFF */
   };

    下面是OS_SchedNew()函数中获取最高优先级的代码:

       y  =  OSUnMapTbl[OSRdyGrp];
       OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);
    y 就是查表得到的最小的那一个组的,上面已经解释过了,优先级的高 3 位表示组,所以左移 3 位到高三位。加上查表得到的该组内的偏移量,就是最高优先级的数值了。

四、结语

    该方法还是挺巧妙的。让每次查找进行几条语句就可以实现了。这个方法可以借鉴到其他地方。


你可能感兴趣的:(uC/OS-II)