多任务操作系统的主要工作是为系统中处于就绪状态的任务分配CPU资源,其中涉及的两个关键是:判断哪些任务处于就绪状态、确定哪个任务应该马上得到执行,即任务调度。
1. 任务就绪表
任务就绪表记录了系统中所有处于就绪状态的任务,从代码上来看它就是一个类型为INT8U的数组OSRdyTbl[]。。系统中的任务为32个时,OSRdyTbl[]就有4个成员。每个成员占据8位,所以OSRdyTbl[]的每一个数据元素对应8个任务,这8个任务称为一个任务组。在就绪表中,以任务优先二进制位,当该位为1时表示对应的任务处于就绪状态,反之为非就绪状态。
考虑到查找效率,uCOS-II定义了一个INT8U的变量OSRdyGrp,该变量的每一位都对应OSRdyTbl[]的一个任务组(即数据的一个成员)。若某任务任务所对应的位置置为1,否则为0。
举例:OSRdyGrp=00001011,那么就意味着OSRdyTbl[0]、OSRdyTbl[1]、OSRdyTbl[3]中有就绪的任务。由图可知,uCOS-II最多可以管理8 * 8 = 64个任务。
任务就绪表是以任务的优先级从低到高排序的,那么想要根据任务的优先级来找到该任务所处于就绪表中位置就轻而易举了:
由于系统至多支持64个任务,所以优先级至多也就到63,即二进制的00111111,只占据低6位,每一个OSRdyTbl[]元素只是占据8,所以只需要用3个二进制位即可表示这8位中的哪一位为1,同理,高3位用于表示至多8个OSRdyTbl[]元素的哪一个元素。即:优先级的高3位二进制位(D5、D4、D3)指明O即:优先级的高3位二进制位(D5、D4、D3)指明OSRdyTbl[]的数组下标n,低3位(D2、D1、D0)指明OSRdyTbl[n]的哪一位数据位。另外,确定OSRdyTbl[]的下标n,也就意味着OSRdyGrp的具体数据位了。
举例:某任务的优先级prio=24,问该任务落在就绪表中的哪一位?
24的二进制位为00011000,D5、D4、D3位011,即OSRdyTbl[]的下标为3,D2、D1、D0为0,即优先级prio=24的任务在OSRdyTbl[0]的第0位。
2. 操作任务就绪表
uCOS-II系统对任务就绪表的操作无非:登记就绪,注销就绪和从就绪表中的所有就绪任务取出最高优先级的任务的任务控制块(TCB)。
2.1 登记就绪
当系统中的某个任务处于就绪状态时,系统会将该任务登记在任务就绪表中,即在该任务的优先级的在就绪表的对应位置1,uCOS-II的实现代码为:
OSRdyGrp |= ptcb->OSTCBBitY;
OSRdyTbl[y] |= ptcb->OSTCBBitX;
ptcb->OSTCBY的值为:
#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);
//...
如上4个变量是任务与就绪表关联的关键,它们被保存在任务的控制块中(TCB),其中ptcb->OSTCBY等于任务优先级的高3位(D5、D4、D3),即为OSRdyGrp、OSRdyTbl[]的数组下标。ptcb->OSTCBX等于任务优先级的低3位(D2、D1、D0)。(ptcb->OSTCBBitY和ptcb->OSTCBBitX也是为查询就绪表高效而设置的)
所以”OSRdyGrp |= ptcb->OSTCBBitY”是置一OSRdyGrp对应OSRdyTbl[]下标值的位,”OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX”是置一OSRdyTbl[]对应成员的位。
2.2 注销就绪
注销就绪即在该任务的优先级的在就绪表的对应位清零,uCOS-II的实现代码为:
INT8U y;
y = OSTCBCur->OST