內核在進行任務調度時,必須知道哪個任務在運行、哪個任務是就緒的最高優先級的任務。實時任務調度的關鍵在于速度,要求無論系統的運行情況如何,調度的時間是確定的,不能把時間都用在調度上。因此就需要設計高效的多任務調度方法。查找高優先級的任務,與正在運行的任務的優先級進行比較以確定是否進行任務切換是內核在每個時鐘中斷都需要做的事情。為滿足這樣的需要,uC/OS-II的開發者采用了就緒表和就緒組這樣的數據結構,圍繞它們又定義了兩張查找表。
就緒組和就緒表的相關定義如下所示:
041448df4tpd7kxpok7h4q.png (5.16 KB, 下載次數: 109)
下載附件
2013-7-14 16:10 上傳
041412pl57p75b5z3iibli.png (13.36 KB, 下載次數: 136)
下載附件
2013-7-14 16:10 上傳
041413ejppqd7yb5m0jm6d.png (3.6 KB, 下載次數: 96)
下載附件
2013-7-14 16:10 上傳
已經知道,OS_LOWEST_PRIO是最低優先級任務的優先級,因為uC/OS-II最多可以同時有64個就緒任務,而優先級是從0開始,因此最大可以設置為63.如果設置為63,則OS_RDY_TBL_SIZE就為8,那么OSRdyTbl最多有8個元素。
OSRdyGrp是就緒組,類型是INT8U,INT8U等同于無符號的字符型,也就是8位無符號數。OSRdyTbl就是每個元素都為8位無符號數的數組,數組中元素的個數是OS_RDY_TBL_SIZE。
如果把OSRdyTbl直接定義為INT8U OSRdyTbl[8]是不是也可以呢?答案是肯定的,但是如果任務數沒有那么多,沒有必要把OS_LOWEST_PRIO設置為63,假設是3,那么只要定義為INT8U OSRdy[1]就可以了,這樣做可以節約內存空間。
uC/OS-II規定,每個就緒的任務在就緒表中的對應位置為1,反之為0。只要就緒表OSRdyTbl[n]所有的位都為0,OSRdyGrp的第n位才為0。
在操作系統還沒有創建任務的時候,就緒表和就緒組如下圖所示:
041414x0j4t3dd4djdd3iz.png (18.72 KB, 下載次數: 93)
下載附件
2013-7-14 16:10 上傳
在上圖中,因為沒有就緒任務,所以就緒表中所有位都是0,即從OSRdyTbl[0]到OSRdyTbl[7]都是0,所以OSRdyGrp也是0。當創建了空閑任務和統計任務后,就緒表和就緒組如下圖所示:
041415mphtgrzibeb1tlbp.png (17.49 KB, 下載次數: 102)
下載附件
2013-7-14 16:10 上傳
在上圖中,創建了優先級最小的兩個任務——空閑任務和統計任務。空閑任務的優先級是63,空閑任務就緒,那么OSRdyTbl[7]的最高位為1.統計任務的優先級是62,統計任務也就緒,那么OSRdyTbl[7]的次高位為1。OSRdyTbl[7]不是0,所以OSRdyGrp的第7位為1。如果我們再創建一個優先級是11的任務,創建后就緒表和就緒組就應該如下圖所示。
041415zr6xo01ri0t51ozf.png (13.15 KB, 下載次數: 91)
下載附件
2013-7-14 16:10 上傳
通過上面3個任務的創建過程可以看出,如果有新的就緒任務,就需要將就緒表中與該任務優先級對應的項置1.如果該就緒任務在第n行,就將OSRdyGrp的第n位置1。
于是,如果有一個優先級為prio的任務就緒,應執行如下的代碼:
041416ghu9dmugy5j93x9a.png (11.41 KB, 下載次數: 103)
下載附件
2013-7-14 16:10 上傳
在任務調度的時候,要查找優先級最高的任務。采用分組管理的方法就是為了使查找的時候時間是確定的,速度是最快的。如果不采用分組管理的方法,那么就要從OSRdyTbl[0]開始查找,如果一直找不到,就要查找到OSRdyTbl[7],所以時間比較長,且不能確定。采用就緒組后,查找程序代碼如下所示:
041417qtu10e6hzv1etv17.png (26.57 KB, 下載次數: 102)
下載附件
2013-7-14 16:10 上傳
可見,獲取就緒任務中的最高優先級的方法是以OSRdyGrp的值為依據查優先級判定表OSUnMapTbl獲得最高優先級任務的高5位,然后將其賦值給y。然后,以OSRdyTbl[y]的值再一次查表,得到低3位,再將高5位左移3位與低3位相或,得到優先級。這樣的查找方法是迅速的,查找時間也是恒定的。但是這樣做的依據是什么呢?
如果我們要找到優先級最高的任務,那么應該先分析OSRdyGrp。假設OSRdyGrp中最低的為1的位為y號位,決定了我們在就緒表中的哪一行來查找優先級最高的任務。也就是說,先查找到就緒表中的行號。有了行號,接下來再找是哪一列,這樣就知道最低優先級的任務是多少了。OSUnMapTbl這張表就是為了達到這樣的目的而設計的!
OSUnMapTbl的定義如下所示:
041417cp5p5zp8tb8wfgfa.png (9.48 KB, 下載次數: 111)
下載附件
2013-7-14 16:10 上傳
首先根據OSRdyGrp查找優先級判定表,原理是根據優先級立即查找到OSRdyTbl[]中對應元素,即OSRdyGrp中從低位到高位第一個為1的位的位置(從0到7)。例如,如果OSRdyGrp為11001000B,那么最低的為1的位是3號位,于是查表得到3,就是說最高優先級在OSRdyTbl[3]中。如果是01001000B,同樣查找到3,這就是程序中為什么有那么多列是相同的原因。
假設OSRdyGrp為0,那么沒有任務就緒,但是在多任務啟動后沒有任務就緒是不可能的,因為至少空閑任務是就緒的,所以我們添一個0占一個位置。假設OSRdyGrp的最低位為1,那么就緒表中的0行有任務就緒,也就是優先級為0~7的任務有就緒的,我們應該去查看OSRdyTbl[0]中是哪一位為1了。OSRdyGrp的最低位為1的情況有很多,但是所有這些情況下查找得到的值都是0.
優先級判定表OSUnMapTbl就是根據一個8位的無符號數的數值來確定最低的為1的位的位置的,OSUnMapTbl[n]就是n的最低的為1的位的位號。
y=OSUnMapTbl[OSRdyGrp]是將就緒組中最低為1的位的位號取出來放在y中,是就緒表中的行號。OSRdyTbl[y]是取得就緒表中對應行的值,OSUnMapTbl[OSRdyTbl[y]]是該行中最低的為1的位的位號,也就是就緒表中的列號。然后(y<<3)是將y左移3位,再加上行號,正好就是最高優先級的任務的優先級。
查找最高優先級的任務也是用了兩條語句,時間快且確定。
最后舉例驗證一下,就緒表和就緒組如下所示:
041418ihvnn77zmz7otk2z.png (17.42 KB, 下載次數: 113)
下載附件
2013-7-14 16:10 上傳
由圖可知,OSRdyGrp為10000010B(十進制130),應對應OSRdyTbl[1],而OSRdyTbl[1]為00001000,故最高優先級任務為8+3=11。用程序代碼計算,OSUnMapTbl[130]為1,y值為1,表示對應1號行,OSRdyTbl[1]的值為00001000B,OSUnMapTbl[OSRdyTbl[y]]的值為3,于是OSPrioHighRdy=1<<8+3=11,驗證成功。
|