大家在看ucos这个实时操作系统时,很难理解的一点是关于就绪任务的。包括任务就绪的标示以及实现实时调度就绪的任务等方法。

下面我一点点地来说一下自己的简单理解,不对的地方请大家指正。

首先,我们说一下优先级,在ucos里支持64个任务,支持基于优先级的任务调度。

64个优先级放在一个8位的无符号数中。用低六位来表示0—63 64个任务。

任务在创建时给她一个符合条件的数值。

下面,我们就来想一想怎么来标示这64种优先级就不就绪。最简单的,弄一个有64位的数组(char Stat[8])。Stat含有64个位。用1表示就绪,0表示不就绪。

至于怎么根据优先级的数值来把Stat相应的位值1或者0那?我们很容易就想到了 “与 ”、“或” 操作。问题又出现了,用八位的数(优先级)来和64为的数(Stat)进行 “与” 或”操作,至于到底置哪一位那?

我们这样想一想,我们应该怎样利用刚才的64位的空间那?

刚才根据最初的想法,这64位的数可以标示任务就不就绪,还有这64个位也可以唯一对应一个任务的优先级。例如,我们可以认为从低位到高位依次是0—63的任务。

好了,我们已经解决了惟一标示优先级和此优先级任务的状态(就绪不就绪)。

具体的操作在ucos是这样的。

定义一个8位的无符号数OSRdyGrp来表示刚才定义的64位数组的下标(0---7)。这个数值其实也就是把原来的64位的数看成8组。大家想一想本来数组就是这个样子的。

现在我们看看优先级,因为毕竟我们是根据优先级来填那个64位的表的。

例如:00100010(优先级是34)我们分析一下,低的三位能代表几个优先级那?8个(0---7)。

那正好8位,能和那个数组的一个char运算。和那个char那?再看4 5 6位这三位。

他们也能代表8中状态。正好对应8个组(用OSRdyGrp的每一位代表一个组号)。呵呵,现在想根据优先级把64位中的哪一位置一就方便了吧。还有,我们组里只要有一个就绪的任务,对应的组的那一位就置一。用这个组号可以方便置位,是吧。

好了,下面说一下在ucos中具体实现的方法.

OSRdyGrp  |=OSMapTbl[prio>>3];

OSRdyTbl[prio>>3]   |=OSMapTbl[prio&0x07];

用这两个式子对上面说的相应位置一或零。

下面说一下这里面的成员:

 

OSRdyGrp一个无符号8位×××数,用来标示组号。

OSRdyTbl上面说的数组名,用来标示每一个优先级的任务。

 

OSMapTbl是一个位图表。

定义如下:

INT8U  const  OSMapTbl[]   = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};

prio 优先级。

下面来说一下怎么实现的置位,先提取优先级4 5 6位,用prio>>3(使优先级右移三位,低三位丢失,得到4 5 6位,而最高两位是0)。

那么根据那三位怎么对相应位置位那,看OSMapTbl[],如果是000 把第一位置一,把OSRdyGrp0x01(即OSMapTbl[0])相或。其他一样原理。

由高三位已经知道了组号,再看低三位的。

OSRdyTbl[prio>>3]   |=OSMapTbl[prio&0x07];

prio&0x07提取低三位,和OSRdyTbl[prio>>3]相或。即把相应位置一。

好了,这样就真正实现了对优先级的惟一标示和状态的标示。

 

 

下面一个关键的问题出现了,我们关键的问题是怎么能快速的找出就绪任务中优先级最高的。

任务调度时要实时。就是查找是时间应该和数量没关系。

我们已经用64位表示了任务的优先级。

查找策略:

我们可以用遍历数组的方法,遍历到第一个1时,停止,计算出这时的优先级,但这样和任务的多少有关系。不符合实时性。

Ucos用的策略是用空间换取时间;

大家想想,是不是用策略找到第一个1就行。因为低位为1 的优先级最小,也就是优先级最高。

那么我们建立一个优先级对应的第一个为一的表格。例如:

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                             */
};
这个表格怎么来的那,我们数组的下标是优先级,8位正好256个状态。256个下标。每个下标对应的数字是第几个数字是一(因为这个是我们最关心的).
例如:优先级是00000100 第二位是一.那么OSUnMapTbl[3]应该是2
有了这个表,我们可以用
y = OSUnMapTbl[OSRdyGrp] /* Find highest priority's task priority number   */
        x = OSUnMapTbl[OSRdyTbl[y]];
        OSPrioHighRdy = (INT8U)((y << 3) + x);

来计算最高的优先级了。

大家细想,每组有8个,组号乘以8加上组里的数字就是最高优先级了。

 

其实,这些过程就是把优先级这个prio表现的属性转移到了就绪表上了,其中优先级的大小属性表现方式更改了一下。又增加了一个优先级的状态属性(即这个优先级的任务就绪没)。

好了,先说到这吧。

版权声明:本文为博主原创文章,未经博主允许不得转载。