uCOS-II系统中的任务就绪表

多任务操作系统的主要工作就是为系统中处于就绪状态的任务分配CPU资源,其中涉及到的两个关键在于:

  1. 判断哪些任务处于就绪态
  2. 判断处于就绪态的任务中哪个任务的优先级最高,确定哪个任务可以优先获得CPU的使用权

任务调度中的就绪表由两部分组成:OSRdyGrpOSRdyTbl[],其中OSRdyGrp是一个8位数据类型的变量OSRdyTbl[]是一个8位数据类型的数组.
图1图1
图2图2

这两幅图是最重要的,看懂了这两幅图,基本上就懂了一大半。
图1:
在OSRdyGrp中,任务按照优先级分组,8个任务为一组,一组占1位,当一组中的8个任务中有任意一个任务进入就绪态后,这个组所在的位也就被置1了。

在OSRdyTbl[]中,它的每一个数据元素对应8个任务,因为他是8位类型数据的数组,所以每个元素的每一个位对应一个任务。

OSRdyGrp和OSRdyTbl[]的联系就是,OSRdyGrp的第n位对应OSRdyTbl[n],当OSRdyTbl[n]这个8位数据的任何一位是1时,OSRdyGrp的第n位置1。

所以,当某个任务进入就绪态时,就绪表OSRdyTbl[]中相应元素的相应位也就置1,此时OSRdyGrp的相应的位也会置1。

图2:

每个任务创建时都会确定任务的优先级,由于系统至多支持64个任务,所以优先级至多也就到63,即二进制的00111111,只占据低6位,uCOSII在任务最低优先级小于等于63时,定义这个优先级是INT8U类型。且高两位D7、D6没有使用到,D5、D4、D3用于指定此任务放在OSRdyTbl[]哪一个元素中,这三位指定的是数组的下标,D2、D1、D0指定此任务放在元素的第几位,指定的是位数,其中的原因是这样的,OSRdyTbl[]的每一个元素有8位,故就可以代表8个任务,在最低优先级小于等于63时,最多8个数据就可以囊括所有的任务优先级。三个二进制位就可以代表8种情况。

在任务控制块OS_TCB中,有几个关键的变量OSTCBY、OSTCBX、OSTCBBitY、OSTCBBitX

#if OS_LOWEST_PRIO <= 63
ptcb->OSTCBY    = (INT8U)(prio >> 3); 
ptcb->OSTCBX    = (INT8U)(prio & 0x07);
ptcb->OSTCBBitY = (INT8U)(1 << ptcb->OSTCBY);
ptcb->OSTCBBitX = (INT8U)(1 << ptcb->OSTCBX);

prio是初始化任务时候传入的优先级。结合图2的讲解,就应该很明白了,其中ptcb->OSTCBY等于任务优先级的高3位(D5、D4、D3),即为OSRdyTbl[]的数组下标,OSRdyGrp的位数,ptcb->OSTCBX等于任务优先级的低3位(D2、D1、D0)。即为OSRdyTbl[ptcb->OSTCBY]此元素的第几位,代表的是位数。

ptcb->OSTCBBitY和ptcb->OSTCBBitX代表的是位掩码,比如ptcb->OSTCBY是5,则ptcb->OSTCBBitY = 0b00100000,这可以很方便的让第5位置位。这就是这个掩码的作用。

找到了下标(即某一个字节),又知道位掩码,就可以对就绪表中该任务的状态进行就绪(置 1 :OSRdyTbl[y] |= OSTCBBitX)和非就绪(清 0 ,OSRdyTbl[y] &=( ~ OSTCBBitX) )操作 , 不需要每次进行操作前都需要通过优先级计算这些信息了。

登记就绪

OSRdyGrp |= ptcb->OSTCBBitY;
OSRdyTbl[ptcb->OSTCBY]  |= ptcb->OSTCBBitX;

基本上结合每个变量的意义,就能明白这两行代码的意思了,其实就是置位OSRdyGrp相应的位和置位OSRdyTbl[]相应元素的相应位。

注销就绪

INT8U   y;
y            =  OSTCBCur->OSTCBY;
OSRdyTbl[y] &= ~OSTCBCur->OSTCBBitX;   //清零OSRdyTbl[y]对应的位
if (OSRdyTbl[y] == 0x00)                //若此时OSRdyTbl[y]已经为0,即所在就绪组已经没有任务就绪
{
    OSRdyGrp &= ~OSTCBCur->OSTCBBitY;  //将OSRdyGrp对应的位清零
}

从就绪表中找出优先级最高的任务

找出优先级最高的任务,要实现不是很简单?只要一个循环遍历接可以了。但是uCOS-II是一个RTOS,对于RTOS来说,系统上的每一个操作所耗费的时间必须是一个常量,如果是去遍历就绪表找出目标任务,也是意味着整个操作所耗时间不一。所以uc/OS-II为了找到任务就绪表中优先级最高的任务,不会从OSRbtTbl[0]开始扫描整个任务就绪表,因为如果是这样的话时间就不能确定。所以对此uc/OS-II准备一张优先级判定表,即OSUnMapTbl[],该表定义如下:

INT8U  const  OSUnMapTbl[] = 
{ 
    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 */
};

首先根据OSRdyGrp查找优先级判定表,原理是根据优先级立即查找到OSRdyTbl[]中对应元素,即OSRdyGrp中从低位到高位第一个为1的位的位置(从0到7)。例如,如果OSRdyGrp为11001000B,那么最低的为1的位是3号位,于是查表得到3,就是说最高的优先级任务在OSRdyTbl[3]中。如果是01001000B,同样查找到3,这就是程序中为什么有那么多列是相同的原因。优先级判定表OSUnMapTbl就是根据一个8位的无符号数的数值来确定最低的为1的位的位置的,OSUnMapTbl[n]就是n的最低的为1的位的位号。

了解了OSUnMapTbl[]优先级判定表的作用后,就可以明白uc/OS-II调度器用于获取优先级最高的就绪任务代码如下:

INT8U   y;
y             = OSUnMapTbl[OSRdyGrp]; //最高优先级所在的任务组     
OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]); //最高优先级任务所在的任务组的位

所以要找出优先级最高的任务,分三步:
  (1) 确定任务组(OSRdyTbl[]的下标)Y:找出OSRedyGrp中为1的最低位Y
  (2) 确定任务组中的位X:找出任务组中OSRdyTbl[Y]中为1的最低位X
  (3 最终确定最高优先级prio = (任务组Y) << 3 | 任务组的上哪一位X

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值