任務就緒表OS_PrioGetHighest函式
本文說明ucos-iii是如何獲取就緒的最高優先順序任務的——OS_PrioGetHighest()。
在說ucos-iii之前,我們不妨先來看看ucos-ii是如何得到相應任務的:
INT8U y;y = OSUnMapTbl[OSRdyGrp];
OSPrioHighRdy = (INT8U)((y << 3u) + OSUnMapTbl[OSRdyTbl[y]]);
以上ucos-ii的獲取函式,ucos-ii定義了u8型別的OSRdyTbl[]陣列,其中每一個u8資料的每一位代表了一個優先順序,當此位為1時,說明此優先順序就緒,否則則沒有就緒,OSRdyTbl[]陣列如下圖:
為了更高效的知道哪個優先順序“段”有就緒任務,ucos-ii又定義了u8型資料OSPdyGrp,此變數中的每一位對應OSRdyTbl[]中的一個元素,即第一位對應OSRdyTbl[0],這樣,當OSPdyGrp=00000001b的時候,說明OSRdyTbl[0]中有就緒任務,即說明優先順序為0~7之間的某一個任務進入了就緒狀態,OSPdyGrp與OSRdyTbl[]的對應關係如圖:
下面我們來討論一下ucos-ii是如何精確找到確定數值的任務優先順序的,我們討論一種比較簡單的情況,我們的任務數在64以下,由於64=2^6,所以用u8型資料的話用其前六位就可以把整個優先順序表示出來,以此為基礎,ucos-ii又把六位拆分為3:3的比例,為什麼這麼分解,原因主要在於ucos-ii採用了點陣圖的方式去拼湊了整個優先順序,位圖表為下圖:
有興趣的可以進行自己拼湊一下,例如優先順序為1,大家可以把此優先順序分別對應為OSRdyTbl[]和OSPdyGrp,之後再逆推過來,你就會發現真的很神奇!當然上面的程式是ucos-ii中假如使用者設定的最大優先順序在64以下時所採用的,更高階的演算法請小夥伴們自行尋找程式進行測試。那麼上述的回憶篇過了,我們就來說一下ucos-iii中是如何進行獲取的,首先還是先貼出程式:
//定義優先順序位對映表
CPU_DATA OSPrioTbl[OS_PRIO_TBL_SIZE];
OS_PRIO OS_PrioGetHighest (void)
{
CPU_DATA *p_tbl;
OS_PRIO prio;
prio = (OS_PRIO)0;
p_tbl = &OSPrioTbl[0];
while (*p_tbl == (CPU_DATA)0) { /* Search the bitmap table for the highest priority */
prio += DEF_INT_CPU_NBR_BITS; /* Compute the step of each CPU_DATA entry */
p_tbl++;
}
prio += (OS_PRIO)CPU_CntLeadZeros(*p_tbl); /* Find the position of the first bit set at the entry */
return (prio);
}
首先宣告,這是整個函式,而不是像ucos-ii,只截取了一部分,所以說不管優先順序多少,此演算法都適用,那這麼流弊的演算法,我們來看看他是怎麼做的吧:首先,ucos-iii依舊定義了一個數組OSPrioTbl[]進行優先順序的逐位對映,但是不同的是,這裡每個元素32位(不愧是為了32Bit和64Bit量身定做),隨後,檢測每個元素是否全零,與ucos-ii一樣,當元素為零時,說明此優先順序“段”中沒有任務就緒,假設我們的prio為60的任務就緒了,那麼顯然OSPrioTbl[0]=0x0000,執行迴圈語句,此處有一個名為DEF_INT_CPU_NBR_BITS的巨集,這個巨集的最終數值為32,也就是一次要跨過32個優先順序,對於例子來說就是說明了0~31的優先順序都沒有就緒,之後指標自加,指向OSPrioTbl[1],因為60在32~63之間,所以OSPrioTbl[1] != 0,跳出迴圈,下面的是“精找”,是利用了彙編語句找到OSPrioTbl[1]中最左端首先為1的位並算出位數,例如prio為60,明顯OSPrioTbl[1]=0001 0000 0000 0000 0000 0000 0000 0000 b,算出的是第18位,注意從0開始計數!所以最終prio = 0+32+18=60,剛好滿足。
就緒表
就緒表由兩部分組成:就緒優先順序位對映表、就緒任務列表
1.就緒優先順序位對映表
記錄哪個優先順序下有任務就緒。
UCOSIII中任務優先順序數由巨集OS_CFG_PRIO_MAX
來配置,UCOSIII中數值越小,優先順序越高,最低可用優先順序就是OS_CFG_PRIO_MAX-1
。
核心函式:
OS_PrioGetHighest()
用於找到就緒了的最高優先順序的任務。
OS_PrioInsert()
置位就緒優先順序位對映表中對應的優先順序的位。
OS_PrinRemove()
清零就緒優先順序位對映表中對應的優先順序的位。
通過上一步我們已經知道了哪個優先順序的任務已經就緒了,但是UCOSIII支援時間片輪轉排程,同一個優先順序下可以有多個任務,因此我們還需要在確定是優先順序下的哪個任務就緒了。
2.就緒任務列表
記錄每一個優先順序下所有就緒任務。
UCOSIII中就緒表由2部分組成:
優先順序位對映表OSPrioTbl[]
:用來記錄哪個優先順序下有任務就緒。
就緒任務列表OSRdyList[]
:用來記錄每一個優先順序下所有就緒的任務。
- 1
- 2
- 3
- 4
- 5
- 6
同一優先順序下如果有多個任務的話最先執行的永遠是HeadPtr所指向的任務!