uCOS-II任务就绪表OSRdyGrp、OSRdyTbl、OSUnMapTbl原理

uCOS版本:V2.91

    使用过uCOS的人应该都知道,每一个uCOS的任务都有一个特定的优先级,就像人的身份证一样,是唯一的,这个优先级在创建的时候就有直到这个任务被删除,整个生命周期都是存在的。优先级越低,任务的优先级就越高。

    本文主要讲述,优先级存在哪里,存放的原理,以及任务切换时是如何查找到优先级高的任务的。

    uCOS的任务优先级存储主要用到以下几个变量:OSRdyGrp,OSRdyTbl,OSUnMapTbl

OSRdyGrp:这是一个INT8U类型的变量,这个变量用来表征哪一组优先级已准备好

OSRdyTbl:这是一个INT8U类型的数组,所有的优先级都保存在这个表中。

OSUnMapTbl:这个表用来查找最高优先级使用。

    以下介绍均认为最大任务数为64.

    首先要介绍的是OSRdyGrp和OSRdyTbl。OSRdyGrp类型为OS_PRIO,也就是INT8U。

    OSRdyGrp表示优先级分组,在UCos中,任务优先级分为8组,每组有8个任务。OSRdyGrp的每一位表示一个分组,例如:OSRdyGrp的值为0x01即二进制位00000001,则表示优先级为0-7的任务中有一个或多个处于就绪状态。

    OSRdyTbl为任务就绪表,这个表中存储了所有任务的就绪状态,表类型为OS_PRIO,也就是INT8U,定义为



这里OS_RDY_TBL_SIZE值为8,所以OSRdyTbl数组相当于一个8行8列的表格,如下:

uCOS-II任务就绪表OSRdyGrp、OSRdyTbl、OSUnMapTbl原理_第1张图片

下面看整个流程。


基本的思路就是把所有就绪的任务优先级存储起来,然后在任务切换时查找优先级最高的任务去执行即可。

任务的优先级存储是任务的创建时进行存储的。

在os_task.c文件中OSTaskCreate(),其中在调用OS_TCBInit()函数进行任务控制快点额初始化中的后面部分,有如下语句:


在这里看下,OSTCBBitX和OSTCBBitY这两个变量的来历。首先他们的类型是OS_PRIO,也就是INT8U,这两个变量的赋值在OS_TCBInit()函数的大概中间位置,这里我们假设最大任务数为64,所以我们只看前面两行和后面两行,

uCOS-II任务就绪表OSRdyGrp、OSRdyTbl、OSUnMapTbl原理_第2张图片

第一行,由任务的优先级右移3位,相当于缩小8倍,用于任务优先级的分组,上面已经讲到任务优先级分为8组。第五行,将这个值赋给OSTCBBitY,最终赋值给OSRdyGrp,意为只要该组有任务就绪,则该位置位。

第二行,取优先级低3位,相当于对8取余,用来计算该优先级在当组的哪一个位置。第6行,将这个值赋给OSTCBBitX,最终设定在OSRdyTbl表中。

此时任务优先级储存完成。

接下来看在任务切换的时候如何查找已就绪的最高优先级。

具体实现在os_core.c文件中的OS_SchedNew()函数中,


我们都知道,在ucos中,任务优先级越低,任务的优先级越高,所以我们要做的就是查找OSRdyTbl表中被置位的最小位置。ucos中,查找的方法是先找到就绪的组,然后再找到这个组中优先级最高的任务,比如说现在有,3个任务就绪,分别是5,20,45,则OSRdyGrp的值为00100101.我们知道,最高优先级是5.要想找到这个5,先找到这个5所在的组,相当于找OSRdyGrp变量所有位中被置位的最低位,这里被置位的最低位是第0位,所以为第0组,查找方法为查表。这里介绍最后一个数组变量OSUnMapTbl,这个数组中存储的是相应的数组下标被置位的最低位。比如5,最低被置位的是第0位,所以OSUnMapTbl[5] = 0,再比如8,最低被置位的是第1位,所以OSUnMapTbl[8] = 1.这样在查找最低位的时候就可以通过查表进行了。

下面举个栗子讲述一下整个流程:

初始化时创建3个任务,优先级分别为5,20,50

优先级为5:

OSTCBY= prio >> 3;           // OSTCBY= 0x00

OSTCBX= prio & 0x07;       // OSTCBX= 0x05

OSTCBBitY  = 1uL << OSTCBY;  //  OSTCBBitY  = 0x01
OSTCBBitX  = 1uL << OSTCBX;  //  OSTCBBitX  = 0x05

OSRdyGrp |= OSTCBBitY ;       //  OSRdyGrp  = 0x01  00000001

OSRdyTbl[OSTCBY] |= OSTCBBitX; // OSRdyTbl[0] = 00100000

优先级为20:

OSTCBY= prio >> 3;           // OSTCBY= 0x02  00000010

OSTCBX= prio & 0x07;       // OSTCBX= 0x04  00000100

OSTCBBitY  = 1uL << OSTCBY;  //  OSTCBBitY  = 0x04  00000100
OSTCBBitX  = 1uL << OSTCBX;  //  OSTCBBitX  = 0x10  00010000

OSRdyGrp |= OSTCBBitY ;       //  OSRdyGrp  = 0x05  00000101

OSRdyTbl[OSTCBY] |= OSTCBBitX; // OSRdyTbl[2] = 00010000

优先级为50:

OSTCBY= prio >> 3;           // OSTCBY= 0x06  00000110

OSTCBX= prio & 0x07;       // OSTCBX= 0x02  00000010

OSTCBBitY  = 1uL << OSTCBY;  //  OSTCBBitY  = 0x00  01000000
OSTCBBitX  = 1uL << OSTCBX;  //  OSTCBBitX  = 0x04 00000100  

OSRdyGrp |= OSTCBBitY ;       //  OSRdyGrp  = 0x45  01000101

OSRdyTbl[OSTCBY] |= OSTCBBitX; // OSRdyTbl[6] = 00000100

注意观察,此时,OSRdyGrp 的值已经从开始的0x00,变为现在的0x45,01000101,任务就绪表如下:

uCOS-II任务就绪表OSRdyGrp、OSRdyTbl、OSUnMapTbl原理_第3张图片

此时,任务就绪表存储已完成,接下来进行任务切换时候的查找。

    y             = OSUnMapTbl[OSRdyGrp];  // y = OSUnMapTbl[0x45] = OSUnMapTbl[69] = 0

    OSPrioHighRdy = (INT8U)((y << 3u) + OSUnMapTbl[OSRdyTbl[y]]);  

    //OSPrioHighRdy = 0+OSUnMapTbl[0x20] 

                                 = 0+OSUnMapTbl[32]

                                 = 0+5

                                 = 5

这样就找到了最高优先级5










你可能感兴趣的:(单片机,RTOS)