詳解UCOS中的任務排程機制
詳解UCOS的任務排程機制
一個作業系統核心提供的最核心的功能就是任務的排程機制,作業系統的核心排程機制有大體有兩種,一種是時間片輪番排程,就是將一個系統週期分為好幾段,第一段時間執行第一個任務,第二段時間執行第二個任務....每一段時間都執行相應的任務。一種就是搶佔式實時核心,即優先順序最高的任務優先執行,不論什麼時候,只要就緒的任務中有比當前正在執行的任務優先順序更高的任務,就暫停當前的任務去執行優先順序最高的任務。UCOS_II就是搶佔式的實時核心。
UCOS中跟任務排程相關的變數如下:
UCOS 一共支援64個任務,任務的優先順序的書越低優先順序越高。我們將64個任務分為8組,每組8個優先順序。OS_EXT INT8U OSRdyGrp; OS_EXT INT8U OSRdyTbl[64];
優先順序 0 ->7 為優先順序組0
優先順序 8 ->15 為優先順序組1
優先順序 16->23 為優先順序組2
優先順序 24 ->31 為優先順序組3
優先順序 32 ->39 為優先順序組4
優先順序 40->47 為優先順序組5
優先順序 48 ->55 為優先順序組6
優先順序 56->63 為優先順序組7
如果第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();
}