UCOS系统源码分析之优先级位图法(算法)

优先级位图法

1 本次算法涉及到的参数变量:

   OSTCBX:   主要存放优先级行数
   OSTCBY:   主要存放优先级列数    
 OSTCBBitX: 主要存放优先级行位数(n行就n行为1)
 OSTCBBitY: 主要存放优先级列位数(n列就n列为1)     
 例:OSTCBX=5,表示第5行,然后用OSTCBBitX表示行位数:00100000

如图所示
该图为不同优先级下对应的行列数 x,y。

2 如何从优先级得到行列数呢?

首先我们可以知道,我们的优先级设定是在63以内的。以优先级15为例。如何得到行列数?
优先级 15,其二进制:00001111。这里需要说明一点,优先级是0~63,因此在任意情况下的优先级化成二进制都是6位, 即00xxxxxx

  1. 所以我们只需操作优先级的低六位即可。在低六位的情况下对高三位,低三位进行操作
    15 >> 00001111 >> 001111 >> 001 111
  2. 优先级15,在上图所示为第1行,第7列
  3. 那001 111 刚好就对应对应起来了。因此001为行,111为列。其代码的编写就是
 ptcb->OSTCBY = (INT8U)(prio >> 3u); //左移三位,00001111变成00000001,即1行
 ptcb->OSTCBX = (INT8U)(prio & 0x07u);//和00000111相与,00001111变成00000111,即7列
 ptcb->OSTCBBitY = (OS_PRIO)(1uL << ptcb->OSTCBY);//1左移OSTCBY得到00000010
 ptcb->OSTCBBitX = (OS_PRIO)(1uL << ptcb->OSTCBX);//1左移OSTCBX得到10000000
这里解释一下(1uL << ptcb->OSTCBY)与OSMAPTbl[ptcb->OSTCBY]功能是一样的,我这边的工程里面没有设立OSMAPTbl[]数组。

3 既然明白了任务优先级与行列的关系,那该如何将优先级存入行列中?

这里用到两个参数
OSRdyGrp :代表行位数,n行n位
OSRdyTbl[]:列位数数组n列n位,数组里存放的是列位数

行列存放在这两个全局变量里面:

OSRdyGrp |= ptcb->OSTCBBitY; //OSRdyGrp直接等于行位数(行位数不等于行数)
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;  //在对应的行数数组内存放列位数
行位数与行数的区别:第3行,行位数即00001000

那现在已经将行位数与列位数都存放到全局变量中了。那我们来举例看看你弄懂了吗?

优先级:23 二进制表示:00 010 111

 1. ptcb->OSTCBY = (INT8U)(prio >> 3u) =00000010 =  2行
    ptcb->OSTCBX = (INT8U)(prio & 0x07u)=00000111= 7列
    ptcb->OSTCBBitY = (OS_PRIO)(1uL << ptcb->OSTCBY)= 00000100行位数
    ptcb->OSTCBBitX = (OS_PRIO)(1uL << ptcb->OSTCBX)=10000000列位数
 2. OSRdyGrp |= ptcb->OSTCBBitY=00000100行位数对应2行 
    OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX= OSRdyTbl[2]=10000000列位数对应7列
 再次声明行数与行位数的关系 n行n位数,3行,那行位数=00001000
 请注意:ptcb为当前任务的结构体指针

总结一下:
①OSRdyGrp 与OSRdyTbl[ptcb->OSTCBY]存放的是行列的位数
②OSRdyTbl[ptcb->OSTCBY]= ptcb->OSTCBBitX,表示在第n行下存了列位数,例如OSRdyTbl[3]=00001000,该任务下第三行存放列数位3列

4 探究一下,存放行列数之后如何取出?

这里会涉及到ucos系统的设计原理。

  1. 首先UCOS会在创建任务时将优先级,栈顶地址,等等参数放置在某结构体指针对应的OS_TCB的变量里,同时该结构体指针是OSTCBFreeList链表中的一员。这个任务就对于了该结构体指针。可以这样理解:任务—结构体指针—指针指向的参数
  2. 当在我们在写ucos时,会创建多个任务,那这些任务的结构体指针全部按顺序排列会在链表里。同时这些结构体指针会指向对应的OSTCB参数,那这些OSTCB参数就包括优先级,栈地址。即不同的任务有不同的结构体指针,不同的结构体指针就对应着不同的优先级,栈地址等等参数。

任务1—结构体指针1—指针指向的参数
任务2—结构体指针2—指针指向的参数

  1. 当我们要做任务切换时,只要这些链表里面最高的优先级对应的任务结构体指针就行了,把这个结构体指针放到就绪列表,就做出了任务切换。

进入正题:如何找出优先级?
① 已知我们之前将优先级通过

OSTCBX:
OSTCBY:
OSTCBBitX:
OSTCBBitY:
注意:这四个参数是存放在结构体指针对应的参数里面的,不是全局变量,因为每个任务的优先级不同,所以存放的值就不同。

上面这四个参数将优先级存放在OSRdyGrp,OSRdyTbl[]中(这两个参数为全局变量)因为方便之后查找最高优先级。
②通过OSRdyGrp,OSRdyTbl[]查找。
下面的数组是个解码数组,将OSRdyGrp,OSRdyTbl[]的值转化优先级(十进制)

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                   */
};

优先级prio通过什么方法转到OSRdyGrp,OSRdyTbl[]。那我们就逆着这个方法转换回去。

就以优先级23为例, 二进制表示:00 010 111

OSRdyGrp |= ptcb->OSTCBBitY=00000100行位数对应2行
OSRdyTbl[ptcb->OSTCBY] | = ptcb->OSTCBBitX= OSRdyTbl[2]=10000000列位数对应7列

那OSRdyGrp=00000100=4

通过解码数据解码

y = OSUnMapTbl[OSRdyGrp]=OSUnMapTbl[00000100]=OSUnMapTbl[4]=2表示第2;       
OSPrioHighRdy = (INT8U)((y<<3u)+OSUnMapTbl[OSRdyTbl[y]])=(INT8U)(2<<3u)+OSUnMapTbl[OSRdyTbl[2]]=0x00000010<<3+OSUnMapTbl[10000000]=00010000+7=16+7=23;
注意:OSRdyTbl[2]=10000000

在这里插入图片描述
那结果出来了,按照原来的方法逆回去就能得到优先级。再通过优先级找到任务的结构体指针就能实现切换任务操作。

最后一个问题,如果我们同时定义了多个任务,那如何从中找出最高优先级?

其实源码的编写者写的很巧妙。那就是或运算符。
在这里插入图片描述
已知OSRdyGrp,OSRdyTbl[]是全局变量,那么或运算就合理了,每当新建一个任务时都会产生一个优先级,这个优先级按照优先级位图法,利用与运算写入OSRdyGrp,OSRdyTbl[]中,那这两个变量里面就包含了很多优先级。
举个例子:优先级:23,对应OSRdyGrp等于00000100;
在此之后我再新建几个任务,这几个任务的优先级分别是9,13,目前存在三个任务其优先级为9,13,23。那按照位图法OSRdyGrp等于00000110;这里面第2位是23的行位数,第一位是9,13的行位数。之后我们逆着方法通过UnMapTbl[]就能从OSRdyGrp,OSRdyTbl[]找到最高优先级。

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值