1. 程式人生 > >詳解UCOS中的任務排程機制

詳解UCOS中的任務排程機制

詳解UCOS的任務排程機制

一個作業系統核心提供的最核心的功能就是任務的排程機制,作業系統的核心排程機制有大體有兩種,一種是時間片輪番排程,就是將一個系統週期分為好幾段,第一段時間執行第一個任務,第二段時間執行第二個任務....每一段時間都執行相應的任務。一種就是搶佔式實時核心,即優先順序最高的任務優先執行,不論什麼時候,只要就緒的任務中有比當前正在執行的任務優先順序更高的任務,就暫停當前的任務去執行優先順序最高的任務。UCOS_II就是搶佔式的實時核心。

UCOS中跟任務排程相關的變數如下:

OS_EXT  INT8U   OSRdyGrp;
OS_EXT  INT8U   OSRdyTbl[64];
UCOS 一共支援64個任務,任務的優先順序的書越低優先順序越高。我們將64個任務分為8組,每組8個優先順序。

優先順序      0 ->7        為優先順序組0 

優先順序      8 ->15      為優先順序組1

優先順序      16->23     為優先順序組2

優先順序      24 ->31    為優先順序組3

優先順序      32 ->39    為優先順序組4

優先順序      40->47     為優先順序組5

優先順序      48 ->55    為優先順序組6

優先順序      56->63     為優先順序組7

OSRdyGrp 是INT8U型別的,OSRdyGrp中的每一位代表每一組中是否有任務進入了就緒態。 

如果第0組任何一個任務進入就緒態  -------->OSRdyGrp |= 00000001;

如果第1組任何一個任務進入就緒態  -------->OSRdyGrp |= 00000010;

如果第2組任何一個任務進入就緒態  -------->OSRdyGrp |= 00000100;

如果第3組任何一個任務進入就緒態  -------->OSRdyGrp |= 00001000;

如果第4組任何一個任務進入就緒態  -------->OSRdyGrp |= 00010000;

如果第5組任何一個任務進入就緒態  -------->OSRdyGrp |= 00100000;

如果第6組任何一個任務進入就緒態  -------->OSRdyGrp |= 01000000;

如果第7組任何一個任務進入就緒態  -------->OSRdyGrp |= 10000000;

總結規律即: OSRdyGrp |= 1<<(組);

OSRdyTbl[8]是一個數組,OSRdyTbl[n]中的每一位代表第n組中的第幾個任務進入了就緒態。

如果第0組的第一個任務進入了就緒態  -------> OSRdyTbl[0] |=  00000001

如果第0組的第七個任務進入了就緒態  -------> OSRdyTbl[0] |=  10000000

如果第2組的第三個任務進入了就緒態  -------> OSRdyTbl[2] |=  00001000

如果第7組的第六個任務進入了就緒態  -------> OSRdyTbl[7] |=  01000000

即 OSRdyTbl[組] |=1<< (任務的優先順序&0X07)   

這裡難懂的原因就是陣列的下表是0->7,所以prio/8得到的優先順序組的範圍是0->7,
但是一個對INT8U進行逐位操作的時候卻是第一位到第八位,要進行轉換所以使這裡比較難懂

所以使一個任務進入就緒態的過程為(prio為任務的優先順序):

x = piro & 0X07;       //任務在優先順序組中的位置 0----->7
y = p >> 3 ;           //任務所處的優先順序組     0----->7
bitX = 1<<x;            
bitY = 1<<y;
OSRdyGrp |= bitY;      //相應的優先順序組的位置1
OSRdyTbl[y]  |= bitX;  //把相應的優先機組中相應的位置1

以優先順序22的任務為例:

x = 22 & 0X07  = 6;          
y = 22 >>3  = 2;
bitX = 1<<6;      //01000000
bitY = 1<<2;      //00000100
OSRdyGrp |= 00000100 ;       //第2個優先順序組中有任務處於就緒態
OSRdyTbl[2] |= 01000000;     //第2個優先順序組中第7個任務處於就緒態

與上面相反,使一個任務脫離就緒態的過程如下:

OSRdyTbl[y] &= ~bixX;  
if(OSRdyTbl[y]==0)
{
    OSRdyGrp &= ~bitY;
}
OSRdyGrp 一共有8位,所以一共有256中組合,假定OSRdyGrp = 11011000,此時的OSRdyGrp代表的意思是:優先順序組3,4,6,7中都有任務進入就緒態了。因為我們只需要處理優先順序最高的任務,所以我們只管OSRdyGrp中第一個二進位制位1所在的位置,即當前最高優先順序任務在第3組中。我們把這256中情況都做這樣的處理構建出這樣一個表,直接查表即可的出當前最高優先順序任務所在的組。
INT8U  const  OSUnMapTbl[256] = {
    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                             */
};

先查出最高優先順序任務所在的組,然後再查出改組中優先順序最高的任務(最先出現1的二進位制位),即可得出最高優先順序任務的優先順序:

y = OSUnMapTbl[OSRdyGrp]; //得到最高優先順序任務所在的組
x = OSUnMapTbl[OSRdyTbl[y]]; //該組中優先順序最高的位
prio = y<<3 + x;           //最高優先順序

跟任務排程相關的函式都在os_core.c檔案中排程的具體函式如下:

該函式的功能是找出就緒表中優先順序最高的任務

void  OS_Sched (void)
{
    #if OS_CRITICAL_METHOD == 3
    OS_CPU_SR  cpu_sr = 0;    //為CPU狀態暫存器分配空間
   #endif


    OS_ENTER_CRITICAL();
    if (OSIntNesting == 0)       //中斷服務程式中不能排程
    {
        if (OSLockNesting == 0)      //排程器上鎖時不能進行排程
       {
            OS_SchedNew();    //找出就緒表中優先順序最高的任務
            if (OSPrioHighRdy != OSPrioCur)        //最高優先順序任務不是當前任務時才進行排程
            {
                OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
                #if OS_TASK_PROFILE_EN > 0
                OSTCBHighRdy->OSTCBCtxSwCtr++;   //統計該任務切換次數
                #endif
                OSCtxSwCtr++;              //統計系統所有任務切換次數
                OS_TASK_SW();       //執行任務切換
            }
        }
    }
    OS_EXIT_CRITICAL();
}