ucosii的任务调度算法

ucosii任务三要素ucosii在CM3中的移植学习中,对于ucosii的任务的基本要素,任务切换的基本流程已经有了认识。任务切换中有一部分是找到当前就绪任务中优先级最高的,今天我们就来看看是如何找到要切换的任务的。

ucosii任务三要素提到一个指针数组OSTCBPrioTbl,这个指针数组中放的是每一个任务控制块(TCB)的地址,并且是以任务的优先级来进行索引的,所以,只要知道了下一个任务的优先级,我们就能找到这个任务的TCB,从而就能完成任务切换。

为了表示系统中所有任务的就绪状态,ucosii创建了一个任务就绪表,其实就是一个数组OSRdyTbl

OS_EXT  OS_PRIO           OSRdyTbl[OS_RDY_TBL_SIZE];       /* Table of tasks which are ready to run    */

我们以当前最大任务数不超过64个为例

OSRdyTbl数组就包括8个元素OSRdyTbl[8],元素类型是8位无符号整型数据。每一个元素的每一位代表任务是否处于就绪态,1表示是就绪态,0表示没有处于就绪态。8个元素就能表示64个优先级的就绪状态。其中0号元素的第0位表示优先级为0的任务,其中0号元素的第1位表示优先级为0的任务,一次类推,如下图。


这样我们可以将其理解成一个8*8的一个矩阵。我们只要知道行号和列号就能知道优先级的值。

在unsoii中 OSRdyGrp变量来指示OSRdyTbl中有哪一个元素不为0,也就表示哪一行的某些位被置了 1,OSRdyGrp中的一位对应OSRdyTbl中的一行


我们先来看创建一个任务时如何给就绪列表OSRdyTbl赋值,假如我们创建一个优先级为29的任务,我们需要做的就是将OSRdyTbl中的第三个元素的第5bit置1,也就是第(29/8)行的第(29%8)bit置1,再换一种说法,行号和列好最大为8,其实就是将十进制29换成了八进制的35,3为行号,5为列号。

在任务控制块中是有行号和列号这两个值的

typedef struct os_tcb {
    OS_STK          *OSTCBStkPtr;           /* Pointer to current top of stack                         */

    struct os_tcb   *OSTCBNext;             /* Pointer to next     TCB in the TCB list                 */
    struct os_tcb   *OSTCBPrev;             /* Pointer to previous TCB in the TCB list                 */

........
    INT32U           OSTCBDly;              /* Nbr ticks to delay task or, timeout waiting for event   */
    INT8U            OSTCBStat;             /* Task      status                                        */
    INT8U            OSTCBStatPend;         /* Task PEND status                                        */
    INT8U            OSTCBPrio;             /* Task priority (0 == highest)                            */

    INT8U            OSTCBX;                /* 这个是OSRdyTbl元素的哪一位 Bit position in group  corresponding to task priority   */
    INT8U            OSTCBY;                /* 这个可以理解成行号,OSRdyTbl中的那个元素Index into ready table corresponding to task priority   */
    OS_PRIO          OSTCBBitX;             /* 1<<OSTCBX,OSRdyTbl元素的值 Bit mask to access bit position in ready table          */
    OS_PRIO          OSTCBBitY;             /* 1<<OSTCBY,OSRdyGrp的值 Bit mask to access bit position in ready group          */

} OS_TCB;

在任务控制块的初始化函数中对这几个值进行了赋值

INT8U  OS_TCBInit (INT8U    prio,
                   OS_STK  *ptos,
                   OS_STK  *pbos,
                   INT16U   id,
                   INT32U   stk_size,
                   void    *pext,
                   INT16U   opt)
{
    OS_TCB    *ptcb;



    OS_ENTER_CRITICAL();
    ptcb = OSTCBFreeList;                                  /* Get a free TCB from the free TCB list    */
    if (ptcb != (OS_TCB *)0) {
        OSTCBFreeList            = ptcb->OSTCBNext;        /* Update pointer to free TCB list          */
        OS_EXIT_CRITICAL();
        ptcb->OSTCBStkPtr        = ptos;                   /* Load Stack pointer in TCB                */
        ptcb->OSTCBPrio          = prio;                   /* Load task priority into TCB              */
        ptcb->OSTCBStat          = OS_STAT_RDY;            /* Task is ready to run                     */
        ptcb->OSTCBStatPend      = OS_STAT_PEND_OK;        /* Clear pend status                        */
        ptcb->OSTCBDly           = 0u;                     /* Task is not delayed                      */
#if OS_LOWEST_PRIO <= 63u   /任务小于64个 8*8*/                                      /* Pre-compute X, Y                  */
        ptcb->OSTCBY             = (INT8U)(prio >> 3u);       /*获取行*/
        ptcb->OSTCBX             = (INT8U)(prio & 0x07u);     /*获取列*/
#else                             /*任务最大为256个 16*16*/                                /* Pre-compute X, Y                  */
        ptcb->OSTCBY             = (INT8U)((INT8U)(prio >> 4u) & 0xFFu);
        ptcb->OSTCBX             = (INT8U) (prio & 0x0Fu);
#endif
                                                                  /* Pre-compute BitX and BitY         */
        ptcb->OSTCBBitY          = (OS_PRIO)(1uL << ptcb->OSTCBY);
        ptcb->OSTCBBitX          = (OS_PRIO)(1uL << ptcb->OSTCBX);
.........

        OSTCBInitHook(ptcb);


        OSTaskCreateHook(ptcb);                            /* Call user defined hook                   */


        OS_ENTER_CRITICAL();
        OSTCBPrioTbl[prio] = ptcb;
        ptcb->OSTCBNext    = OSTCBList;                    /* Link into TCB chain                      */
        ptcb->OSTCBPrev    = (OS_TCB *)0;
        if (OSTCBList != (OS_TCB *)0) {
            OSTCBList->OSTCBPrev = ptcb;
        }
        OSTCBList               = ptcb;
        OSRdyGrp               |= ptcb->OSTCBBitY;         /* Make task ready to run   赋值                */
        OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
        OSTaskCtr++;                                       /* Increment the #tasks counter             */
        OS_EXIT_CRITICAL();
        return (OS_ERR_NONE);
    }
    OS_EXIT_CRITICAL();
    return (OS_ERR_TASK_NO_MORE_TCB);
}
 
 

上述步骤就完成了对任务就绪表的赋值工作。现在做反方向的工作,知道了OSRdyGrp和OSRdytbl的值,如何找到最高优先级。注意,这里是最高优先级,我们需要用到位图法,位图法是用空间换取时间的方法。

列举OSRdyGrp的几种情况

OSRdyGrp=1>>>>>>OSRdyGrp的第0bit被置1,可以从OSRdytbl第0行找哪一位被置1,从而找到最高优先级

OSRdyGrp=2>>>>>>OSRdyGrp的第1bit被置1,可以从OSRdytbl第1行找哪一位被置1,从而找到最高优先级

OSRdyGrp=3>>>>>>OSRdyGrp的第0bit和第1bit都被置1,应从OSRdytbl第1行找哪一位被置1

OSRdyGrp=4>>>>>>OSRdyGrp的第2bit被置1,应从OSRdytbl第2行找哪一位被置1

OSRdyGrp=4>>>>>>OSRdyGrp的第2bit和第1bit被置1,应从OSRdytbl第0行找哪一位被置1

以此类推

..........

OSRdyGrp=255>>>>>>OSRdyGrp的第0bit---第7bit都被置1,应从OSRdytbl第0行找哪一位被置1

也就是把OSRdyGrp的256种情况都列出来,每一种情况对应着要找出的一个结果,

ucosii中表示如下

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





找出8行,就需要2的8次方的一个数组,同理找8列的时候也用这个数组,8*8就是64个优先级了


看一下在ucosii中的实际例子

static  void  OS_SchedNew (void)
{
#if OS_LOWEST_PRIO <= 63u                        /* See if we support up to 64 tasks  小于64个任务时                 */
    INT8U   y;


    y             = OSUnMapTbl[OSRdyGrp];            /*这两行就是在找到最高优先级了*/
    OSPrioHighRdy = (INT8U)((y << 3u) + OSUnMapTbl[OSRdyTbl[y]]);
#else                                            /* We support up to 256 tasks   最高支持256个任务                      */
    INT8U     y;
    OS_PRIO  *ptbl;


    if ((OSRdyGrp & 0xFFu) != 0u) {
        y = OSUnMapTbl[OSRdyGrp & 0xFFu];
    } else {
        y = OSUnMapTbl[(OS_PRIO)(OSRdyGrp >> 8u) & 0xFFu] + 8u;
    }
    ptbl = &OSRdyTbl[y];
    if ((*ptbl & 0xFFu) != 0u) {
        OSPrioHighRdy = (INT8U)((y << 4u) + OSUnMapTbl[(*ptbl & 0xFFu)]);
    } else {
        OSPrioHighRdy = (INT8U)((y << 4u) + OSUnMapTbl[(OS_PRIO)(*ptbl >> 8u) & 0xFFu] + 8u);
    }
#endif
}

对于256任务的情况,稍微会复杂一些,前面64个任务是8行*8列,256则是16*16.但我们没必要去做一个2的16次方的位图,太大了,65535个字节空间,太浪费。把256分成(2*8行)*(2*8)列就ok了,加上两个if else判断一下就ok了

#if OS_LOWEST_PRIO <= 63u
typedef  INT8U    OS_PRIO;
#else
typedef  INT16U   OS_PRIO;
#endif
首先对于数据类型会有个变化,大于64个任务时,任务优先级的相关变量用16位表示。


#if OS_LOWEST_PRIO <= 63u                                         /* Pre-compute X, Y                  */
        ptcb->OSTCBY             = (INT8U)(prio >> 3u);
        ptcb->OSTCBX             = (INT8U)(prio & 0x07u);
#else                                                             /* Pre-compute X, Y                  */
        ptcb->OSTCBY             = (INT8U)((INT8U)(prio >> 4u) & 0xFFu);
        ptcb->OSTCBX             = (INT8U) (prio & 0x0Fu);
#endif
                                                                  /* Pre-compute BitX and BitY         */
        ptcb->OSTCBBitY          = (OS_PRIO)(1uL << ptcb->OSTCBY);
        ptcb->OSTCBBitX          = (OS_PRIO)(1uL << ptcb->OSTCBX);
 
 

小于64个任务时,优先级转换位8进制数,作为行号列号,大于64就直接使用16进制数就可以了。初始化就这样,很简单

寻找最高优先级任务时,把行和列都一分为二即可(2*8)*(2*8)

    if ((OSRdyGrp & 0xFFu) != 0u) {
        y = OSUnMapTbl[OSRdyGrp & 0xFFu];
    } else {
        y = OSUnMapTbl[(OS_PRIO)(OSRdyGrp >> 8u) & 0xFFu] + 8u;
    }
    ptbl = &OSRdyTbl[y];
    if ((*ptbl & 0xFFu) != 0u) {
        OSPrioHighRdy = (INT8U)((y << 4u) + OSUnMapTbl[(*ptbl & 0xFFu)]);
    } else {
        OSPrioHighRdy = (INT8U)((y << 4u) + OSUnMapTbl[(OS_PRIO)(*ptbl >> 8u) & 0xFFu] + 8u);
    }











猜你喜欢

转载自blog.csdn.net/u012142460/article/details/79410117
今日推荐