1. 程式人生 > >任務就緒表OS_PrioGetHighest函式

任務就緒表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[]:用來記錄每一個優先順序下所有就緒的任務。

struct  os_rdy_list {
    OS_TCB           *HeadPtr    //用於建立連結串列,指向連結串列頭
    OS_TCB           *TailPtr;   //用於建立連結串列,指向連結串列尾
    OS_OBJ_QTY       NbrEntries; //此優先順序下的任務數量
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

同一優先順序下如果有多個任務的話最先執行的永遠是HeadPtr所指向的任務! 
就緒任務列表