UCOSII源码分析五——任务优先级与任务调度

一、任务优先级与任务调度

  1. 任务切换,先保存正在运行任务的当前状态(context),即CPU寄存器中的全部内容,这些内容保存在任务的当前状态保存区(task’s context storage area)也就是任务自己的栈区之中。入栈工作完成后,就要把下一个将要运行的任务的当前状态从该任务的栈中重新装入CPU的寄存器,并开始下一个任务的运行
  2. 做任务切换所需要的时间取决于CPU有多少寄存器要入栈
    内核负责管理各个任务,或者说为每个任务分配CPU时间,并负责任务之间的通信,内核提供的基本服务就是任务切换。
  3. 任务只会在OS_Sched()和OSIntExit()中进行切换。OSIntExit()是退出中断后,会寻找就绪任务切换一次
  4. 任务切换的实际操作:将被挂起任务的寄存器入栈,将就绪任务保存在栈里的寄存器数据出栈,恢复到硬件寄存器中去。

ucos ii 如何如何进行任务调度?如何选择优先级最高的任务?
优先级prio是一个无符号的8位数,但是只有低6位有效,0x111111就是63,所有为啥是任务优先级一共有64个
使用查表方式进行任务切换,因为查表法具有确定的时间,增加了系统的可预测性,uC/OS中所有的系统调用时间都是可确定的

分析从OSTimeDly(n)(有很多函数可以引起任务调度)函数开始,OSTimeDly(n)一般会被任务函数while(1)中任务调用,调用OSTimeDly(n)实际上调用OS_Sched()函数,在OS_Sched()内部实现获取最高优先级的操作(函数OS_SchedNew (void))。
当调用任务创建函数

INT8U  OSTaskCreate (void (*task)(void *p_arg),
                    		 void    *p_arg,
                    		 OS_STK  *ptos,
                    		 INT8U    prio )

时(其中参数prio为该任务优先级),函数内部调用OSTaskStkInit(task, p_arg, ptos, 0u)函数,该函数用来初始化任务控制块,并进行任务优先级设置的,其中有几个非常重要的变量:

ptcb->OSTCBY             = (INT8U)(prio >> 3u);
ptcb->OSTCBX             = (INT8U)(prio & 0x07u);
ptcb->OSTCBBitY          = (OS_PRIO)(1uL << ptcb->OSTCBY);
ptcb->OSTCBBitX          = (OS_PRIO)(1uL << ptcb->OSTCBX);
OSRdyGrp               |= ptcb->OSTCBBitY;  
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;

从变量赋值可以看出,ptcb->OSTCBY为prio的第3 ~ 5 位,ptcb->OSTCBX为prio的第0 ~ 2 位,ptcb->OSTCBBitY 为将1 左移ptcb->OSTCBY位,ptcb->OSTCBBitX 为将1 左移ptcb->OSTCBX位,OSRdyGrp 为ptcb->OSTCBBitY值,OSRdyTbl[ptcb->OSTCBY为ptcb->OSTCBBitX值。例如,当优先级为12(0x00 001 100)时有:

ptcb->OSTCBY             =  0x0000 0001 =  1  
ptcb->OSTCBX             =  0x0000 0100 =  4
ptcb->OSTCBBitY          = 	0x0000 0010 
ptcb->OSTCBBitX          =  0x0001 0000 

最后得出:

OSRdyGrp                =  0x0000 0010 
OSRdyTbl[ptcb->OSTCBY] = OSRdyTbl[1]  =  0x0001 0000

下面对这两个变量进行分析:
1、 OSRdyGrp表示当前有那些任务就绪,系统将64个任务分成8组,每一组8个,这样8位的 OSRdyGrp每一Bit就能表示一组,比如bit0表示0 ~ 7任务,bit1代表815任务。当一组中有任意一个任务就绪时,该Bit就值1,比如815中有任务就绪,那Bit1就是1
2、 OSRdyTbl[63/8 + 1]任务就绪表,共8个元素,每个元素8位,这样正好就64个任务,每一个Bit对应一个任务,比如OSRdyTbl[0]的bit0bit7对应07任务。如果任务就绪,对应的位置1。
为了更加直观的理解,画张表格:
OSRdyGrp OSRdyTbl[] 对应优先级
Bit 0 OSRdyTbl[0] 0 ~ 7
Bit 1 OSRdyTbl[1] 8 ~ 15
Bit 2 OSRdyTbl[2] 16 ~ 23
Bit 3 OSRdyTbl[3] 24 ~ 31
Bit 4 OSRdyTbl[4] 32 ~ 39
Bit 5 OSRdyTbl[5] 40 ~47
Bit 6 OSRdyTbl[6] 48 ~ 55
Bit 7 OSRdyTbl[7] 56~ 63
例如优先级12 则对应与OSRdyGrp Bit 1置位(0x0000 0010)与OSRdyTbl[1] ,而OSRdyTbl[1]的值应该为0x0001 0000,此时表示优先级为12的任务就绪了。
但是当有任务就绪的时候是如何找到最高点的优先级,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                   */
};

由变量OSRdyGrp(8位)随机位为1则有256中可能,表中全部列出,所以 OSUnMapTbl的作用就是用表来快速查找当前就绪的最高优先级任务。换句话说,任意多个任务就绪后其最先执行的最高优先级在表中查找。具体实现利用下面三个赋值式。

y = OSUnMapTbl[OSRdyGrp]; 		//获取优先级的5、4、3位
x = OSUnMapTbl[OSRdyTbl[y]];		//获取优先级的2、1、0位

OSPrioHighRdy = (INT8U)((y << 3u) + x);//获取出当前已经就绪的最高优先级任务
上述过程找到优先级最高的任务,为了便于理解举个例子正向推导。
若任务12 和任务22 同时就绪,那么理论应该是12 先执行,
对于任务12就绪则:

OSRdyGrp              =  0x0000 0010 
        OSRdyTbl[ptcb->OSTCBY]  = OSRdyTbl[1]  =  0x0001 0000

对于任务22就绪则:

OSRdyGrp              =  0x0000 0100 
        OSRdyTbl[ptcb->OSTCBY]  = OSRdyTbl[2]  =  0x0100 0000

则:

OSRdyGrp = 0x0000 0110 = 6
OSRdyTbl[1] =  0x0100 0000
OSRdyTbl[2]  =  0x0100 0000

y  = OSUnMapTbl[OSRdyGrp] =OSUnMapTbl[6] = 1;
x  = OSUnMapTbl[OSRdyTbl[y]] = OSUnMapTbl[OSRdyTbl[1]]= OSUnMapTbl[16] = 4

最后:OSPrioHighRdy = (INT8U)((y << 3u) + x) = 8 + 4 = 12(执行该最高优先级),同理其他优先级就绪一样。
Y的来源,Y是最高优先级的高三位。OSRdyGrp一共8bit,那Y就是OSRdyGrp中最低位为1的位;X的来源,X是最高优先级的低三位。首先要找最高优先级,那么如果在同一组内,就是OSRdyTbl的一个元素里面,最低位是1的就是优先级最高的。举例OSRdyTbl[0] =0x0A;//0b00001010,这一位上有任务1和3都就绪,任务1优先级更高,就是最低位是1的就是优先级最高的。那么X就是OSUnMapTbl中最低位为1的位。
此外,在延时函数OSTimeDly(n)中,可以看到赋值:

y  =  OSTCBCur->OSTCBY;  
OSRdyTbl[y] &= (OS_PRIO)~OSTCBCur->OSTCBBitX;
if (OSRdyTbl[y] == 0u) {
    OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY;}

这段代码的功能就是将当前运行的任务的相应位清零,让任务处于非就绪状态。
最后,只看很难理解,要自己动手推导一遍!!!

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值