μC/OS Ⅱ- 任务就绪表的操作

就绪表和就绪组的作用:

  1. 满足内核在每个时钟中断查找最高优先级的任务,与正在运行的任务优先级进行比较以确定是否进行任务切换。
  2. 就绪组和就绪表的采用确保了任务调度的时间是一个确定值(一个常量)。

就绪组和就续表定义的相关代码:

typedef  unsigned char  INT8U;
#define  OS_RDY_TBL_SIZE  ((OS_LOWEST_PRIO)/8 + 1)
INT8U  OSRdyGrp; /* 定义就绪组 */
INT8U  OSRdyTbl[OS_RDY_TBL_SIZE]; /* 定义就绪表 */
  1. OS_LOWEST_PRIO顾名思义Operation System Lowest Priority,假设共有10个就绪任务,则OS_LOWEST_PRIO = 9。
  2. μC/OS最多可以有64个就绪任务,所以最多也就有64个任务优先级(0~63),因为优先级是从0开始的。
  3. 当OS_LOWEST_PRIO取最大值63的时候,OS_RDY_TBL_SIZE =(63/8 + 1)= 8;那么OSRdyTbl最多有8个元素。
  4. 就绪组的本质就是一个字符型变量,它的每一位对应一组,最多8组(0~7)。
  5. 就绪表的本质就是一个字符型数组,最多8个元素,每个元素8位,共64位,对应64个优先级(0~63)。
  6. 数组元素的个数为OS_RDY_TBL_SIZE与就绪的任务数有关,他们满足:OS_RDY_TBL_SIZE = ((OS_LOWEST_PRIO)/8 + 1)。

任务的登记:     

  那么就绪表和就绪组和就绪的任务有什么关系呢?我的理解是这样的,就绪的任务决定就绪组和就绪表的值。通过就绪组和就绪表就能查找出最高优先级的就绪任务。系统每就绪一个任务,都会在就绪组和就绪表中登记,就绪组和就绪表的值和就绪的任务一一对应。

图1-1

  1. 当操作系统还没创建任务的时候,就绪组OSRdyGrp的值为0x00,就绪表元素的值也为0x00。
  2. 当系统创建了空闲任务和统计任务,就绪表的值就相应的改变了。空闲任务的优先级是63,统计任务的优先级是62。
  3. μC/OS规定,每个就绪的任务在就绪表中对应位置为1,反之为0。根据上面就绪表的分布图可知就续表元素的值OSRydTbl[7] = 0B11000000。
  4. 只要就续表OSRdyTal[n]中有一位不为0,那么就绪组OSRydGrp对应位置就为1,即第n位为1。所以此时OSRdyGrp = 0B10000000。
  5. 到第4步我们就完成了对空闲任务和统计任务的登记,可以看出对任务的登记,实质上就是对变量OSRdyGrp和数组元素OSRydTbl[n]赋值。
  6. 那么,如果我们想对任意优先级数的就绪任务登记该怎么做呢?下面两行代码就实现了在就绪表中添加给定优先级(prio)任务的作用;
1               OSRdyGrp |= OSMapTbl[prio>>3];
2               OSRdyTbl[prio>>3] |= OSMapTbl[prio&0x07];
  1. 先看第一条代码:prio>>3就相当于prio除以8,得到的结果就是优先级为prio的任务所在的组。比如说任务的优先级为63,那么63>>3 = 7;所以优先级为63的任务在第七组,和就绪表完全一致,如图1-1所示。并且采用异或操作可以保证新登记的就绪任务,不会没有影响到之前已就绪任务的登记信息;
  2. 再看第二条代码:prio&0x07就相当于取prio的低三位,得到的结果就是优先级为prio的任务在就绪表中所对应的位。比如说任务的优先级为63,那么63&0x07 = 7;所以优先级为63的任务就对应第7组OSRdyTbl[7]的第7位。本条代码同样采用了异或操作,目的也是保证不影响其他任务的就绪状态。
  3. 优先级为prio的任务,其中prio为uint8_t型,prio的最大值为63(0x0011 1111),所以我们只用到了prio的低六位:0x00xxxyyy;其中高三位xxx对应就绪组中的位,低三位yyy对应就绪表中的位。所以在第一条代码中,我们把prio>>3即获得了xxx的值(0~7);第二条代码中把prio&0x07即获得了yyy的值(0~7);
  4. 再来看OSMapTbl这个数组,该数组已经定义好,它的8个元素分别是:
 
1 OSMapTbl[0]=00000001B
2 OSMapTbl[1]=00000010B
3 OSMapTbl[2]=00000100B
4 OSMapTbl[3]=00001000B
5 OSMapTbl[4]=00010000B
6 OSMapTbl[5]=00100000B
7 OSMapTbl[6]=01000000B
8 OSMapTbl[7]=10000000B

  至此,构成了uC/OS-II的8X8的任务就绪表,可以表示0~63共64个优先级,这也是μC/OS Ⅱ支持的最大任务数为64的由来。

任务的注销:

注销,就是说,从任务就绪表中将待注销任务的对应位置0。

1 if ( ( OSRdyTbl[prio >> 3] &= ~OSMapTbl[prio & 0x07] )  == 0)
2     OSRdyGrp &= ~OSMapTbl[prio >> 3];

注意:

  1. OSRdyTbl[prio>>3]所有的位都是0时,OSRdyGrp 的相应位才清零(即对应行一个就绪任务都没有时,OSRdyGrp才为0)。所以要进行判断
  2. OSRdyTbl[prio>>3] 里面可能还包含其他位为1,即在RdyTbl[prio>>3] 中  还有其他就绪任务,这时候所对应的OSRdyGrp 的位还是1,直到RdyTbl[prio>>3] =0,表示没有任务就绪时才应将相应的OSRdyGrp里面的位置0

以上第一行代码将就绪任务表数组OSRdyTbl[]中相应元素的相应位清零;同时做一个判断,判断OSRdyTbl[prio>>3]是否已全部为0,若全部为0,则表示改组任务全都不处于就绪状态,此时可把OSRdyGrp置为0。

任务的查找:

根据X和Y倒推算任务优先级prio:

只需将以上运算倒过来即可:prio = [Y<<3] + X;

例如:刚才上面的例子里,Y = 7,X = 7,则:

1  prio = [Y<<3] + X = [7<<3] + 7
2                    =(111B<<3)+111B
3                    =111000B+111B
4                    =111111B
5                    =63D

因此,进入就绪态的任务优先级为63。

OSRdyTbl[ ]的元素(共8个元素,每个元素为8位;由此可见,任务就绪表就是一个从结构上来看,二维数组)构成8X8的就绪表,OSRdyGrp只表示就绪表的Y轴(所在行),也就是OSRdyGrp 中的每一位表示 8 组(行)任务中每一组(所在行)中是否有进入就绪态的任务。

注意OSRdyGrp和OSRdyTbl[ ]的元素都是按位进行运算的。

最高优先级就绪任务的查找:

       系统调度器总是把CPU控制权交给优先级最高的就绪任务,因此调度器就必须具有从任务就绪表中找出最高优先级任务的能力。

       基本的查找的思路是在任务就绪表里,从上至下,从右至左,挨个来找,但这需要大量的判断,因此花费很长时间。

       快速方法:根据y=OSRdyGrp( 所在组(行) )和OSRdyTbl[y](所在位)在优先级判定表OSUnMapTbl[ ]中,进行查表计算操作,即可快速计算出优先级最高的那个就绪任务。

OSUnMapTbl[ ]如下所示:

 
 1 INT8U const OSUnMapTbl[256] = {
 2     0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,  
 3     4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,      
 4     5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,      
 5     4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,      
 6     6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,      
 7     4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,      
 8     5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,      
 9     4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,      
10     7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,      
11     4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,      
12     5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,      
13     4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,      
14     6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,      
15     4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,      
16     5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,      
17     4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0       
18 };

计算代码如下:

1 y = OSUnMapTbl[OSRdyGrp];         //最高优先级任务所在组(行)
2 x = OSUnMapTbl[OSRdyTbl[y]];      //最高优先级任务所在的位
3 prio = (y << 3) + x;              //还原为优先级

注:

1.OSUnMapTbl[]中的每个元素,表示的是从0x00—0xFF的每个数的二进制   

数表示中,最低位1出现的位置。

2.OSUnMapTbl[]中的每个元素,在0到7之间

参考来源:http://www.cnblogs.com/gylei/archive/2012/05/31/2528776.html

posted @ 2013-03-13 21:27  此岸幸福  阅读(1864)  评论(0)    收藏  举报