大家在看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 把第一位置一,把OSRdyGrp和0x01(即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表现的属性转移到了就绪表上了,其中优先级的大小属性表现方式更改了一下。又增加了一个优先级的状态属性(即这个优先级的任务就绪没)。
好了,先说到这吧。
版权声明:本文为博主原创文章,未经博主允许不得转载。