任務的登記:
1 OSRdyGrp |= OSMapTbl[prio>>3]; 2 OSRdyTbl[prio>>3] |= OSMapTbl[prio&0x07];
這兩行代碼就實現了在就緒表中添加給定優先級(prio)任務的作用;
想要徹底明白這兩行代碼,我們首先要對prio有了解。優先級prio,范圍從[0:63],用二進制數表示,就是000000B~111111B。其中只用到了8位字長的低6位。這低六位又可以分為低三位和高三位:
1 eg: 63=111 111B 2 prio>>3 //即取prio的高三位,(綠色的3位);表示的是任務所在的組,即任務就緒表的Y坐標; 3 prio & 0x07 //即取prio的低三位(紅色的三位);表示的是任務所在的位,即任務就緒表的X坐標。
OSRdyGrp是位可操作的,它的每一位對應Y坐標從0~7,表示任務就緒表的行,如果這一行中有任何一個優先級的任務就緒,就將它的對應位置1;
同理,數組OSRdyTbl[ ] 表示的是就緒表的每一行的內容,它的每個元素,也都是位可操作的,每個數組下標,表示Y坐標,即所在行,每個數組元素的內容,對應所在行的8個元素,也就是就緒表中每一行的8列。至此,構成了uC/OS-II的8X8的任務就緒表,可以表示0~63共64個優先級,這也是μC/OS Ⅱ支持的最大任務數為64的由來。
再來看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
下面回來看最初的兩行代碼:
(1):prio>>3,就是只取prio的高三位,即任務所在的行(即坐標Y=prio>>3),將Y坐標填入數組OSMapTbl[Y]的下標中,OSMapTbl[Y]的值與OSRdyGrp做位或,將新就緒的任務所在的行所對應的OSRdyGrp的位 置1,並且保持其他位不變,如此一來,就新登記了一條就緒任務,並且沒有影響到之前已就緒任務的登記信息;
例如,本例中,假設prio>>3 得到OSMapTbl[prio>>3]=OSMapTbl[7] = 10000000B,再與OSRdyGrp做位或,即將OSRdyGrp的第8位 置為了1,並且沒有改變其他位,同時沒有影響到之前的就緒任務的已登記信息。
(2):prio&0x07,就是只取prio的低三位,即任務所在的位(即坐標X =prio&0x07),將X坐標填入數組OSMapTbl[X]下標中,OSMapTbl[X]與OSRdyTbl[Y]做位或,將OSRdyTbl[Y]對應位 置1,表示該行的第X位有任務進入就緒態,注意第X位要從低端算起,也就是表格的右端開始算起;
例如:剛才已經算出Y坐標 = 7,本例中,prio & 0x07 = 坐標X = 7 ,OSMapTbl[ 7 ] = 10000000B,將10000000與OSMapTbl[7]做位或,即將OSMapTbl[7]的第8位置1,表示該位的任務進入就緒態;如此,新就緒的任務登記完成,也保證了不影響其他任務的就緒狀態。
任務的注銷:
注銷,就是說,從任務就緒表中將待注銷任務的對應位 置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之間