|
uc/OS 任務(wù)調(diào)度機(jī)制
內(nèi)核的核心任務(wù)是任務(wù)調(diào)度機(jī)制,為了對(duì)uC/OS進(jìn)行分析,我們從任務(wù)調(diào)度開(kāi)始。在uC/OS中,一個(gè)任務(wù)通常是一個(gè)無(wú)限循環(huán),程序具有如下的結(jié)構(gòu),后面我將解釋為什么會(huì)有這種結(jié)構(gòu)。從下面的結(jié)構(gòu)可以看出一個(gè)任務(wù)就像其他C函數(shù)一樣;而且,既然任務(wù)是一個(gè)無(wú)限循環(huán),我們可以想象到它一定不會(huì)返回任何的數(shù)據(jù),所以返回類型應(yīng)該定義為void。
程序:
------------------------------------------------------------ void mytask(void *pdata) { for (;;) { do something; waiting; do something; } } uC/OS可以管理64個(gè)任務(wù),但目前的版本系統(tǒng)占用了兩個(gè)任務(wù),還保留了其他六個(gè)任務(wù),故用戶可以使用56個(gè)任務(wù)。每個(gè)任務(wù)必須賦予一定的優(yōu)先級(jí),優(yōu)先級(jí)數(shù)越高,優(yōu)先級(jí)越低,所以0級(jí)優(yōu)先級(jí)的任務(wù)有最高的優(yōu)先級(jí)。通過(guò)在OS_CFG.H文件中定義宏OS_LOWEST_PRIO可以決定系統(tǒng)的任務(wù)的個(gè)數(shù)。系統(tǒng)目前占用的兩個(gè)任務(wù)為空閑任務(wù)IDLE TASK和統(tǒng)計(jì)任務(wù)STAT TASK。當(dāng)沒(méi)有其他任務(wù)進(jìn)入就緒狀態(tài)時(shí)空閑任務(wù)投入運(yùn)行,空閑任務(wù)什么也不做,只是簡(jiǎn)單的將計(jì)數(shù)器加1,這個(gè)計(jì)數(shù)器可以用來(lái)統(tǒng)計(jì)CPU的利用率。
uC/OS下每個(gè)任務(wù)可以有如下五種狀態(tài)。
休眠態(tài)(dormant):指任務(wù)駐留在程序空間中,還沒(méi)有交給內(nèi)核管理。把任務(wù)交給內(nèi)核是通過(guò)調(diào)用OSTaskCreate( )或OSTaskCreatExt( )實(shí)現(xiàn)的。
就緒(Ready):當(dāng)任務(wù)一旦建立,這個(gè)任務(wù)就處于就緒態(tài)準(zhǔn)備運(yùn)行。任務(wù)可以動(dòng)態(tài)的被另一個(gè)程序建立,也可以在系統(tǒng)運(yùn)行開(kāi)始之前建立。通過(guò)調(diào)用OSTaskDel( )使任務(wù)返回到休眠態(tài)。就緒態(tài)的任務(wù)都放在就緒列表中。在任務(wù)調(diào)度時(shí),指針OSTCBHighRdy指向優(yōu)先級(jí)最高的就緒任務(wù),也就是立刻就要運(yùn)行的任務(wù)。 運(yùn)行(Running):準(zhǔn)備就緒的最高優(yōu)先級(jí)的任務(wù)獲得CPU的控制權(quán),從而處于運(yùn)行態(tài)。指針OSTCBCur指向正在運(yùn)行的任務(wù)。
等待或掛起(Pending):正在運(yùn)行的任務(wù)由于調(diào)用延時(shí)函數(shù)OSTimeDly( )或等待事件信號(hào)量的來(lái)臨而將自身掛起,因而處于等待或掛起態(tài)。因?yàn)榈却呈录粧炱鸬娜蝿?wù)注冊(cè)在該事件的等待列表中。
中斷態(tài)(Interrupt):正在運(yùn)行的任務(wù)可以被中斷,除非是該任務(wù)將中斷關(guān)閉。被中斷的任務(wù)進(jìn)入中斷服務(wù)程序(ISR)。如果中斷服務(wù)程序使一個(gè)更高優(yōu)先級(jí)的任務(wù)準(zhǔn)備就緒,這中斷服務(wù)程序結(jié)束后,則更高優(yōu)先級(jí)的任務(wù)開(kāi)始運(yùn)行程序。
任務(wù)被創(chuàng)建后,其狀態(tài)用8位字節(jié)變量OSTCBStat表示,目前只用了低四位如下所示(圖4.1)。如果某位置為1,表示任務(wù)正在等待該位表示的事件;可以復(fù)合使用這些標(biāo)志,表示任務(wù)在同時(shí)等待多個(gè)事件的發(fā)生;如果所有位均為0,表示任務(wù)處于就緒狀態(tài),一旦符合條件(優(yōu)先級(jí)最高),即可投入運(yùn)行。
uC/OS下任務(wù)的狀態(tài)轉(zhuǎn)移如下(圖4.2)所示。每個(gè)任務(wù)在被創(chuàng)建的時(shí)候,一個(gè)稱為任務(wù)控制塊(task control blocks)的數(shù)據(jù)結(jié)構(gòu)將被賦值。
內(nèi)核在初始化的時(shí)候?qū)⑺锌捎玫娜蝿?wù)控制塊通過(guò)指針*OSTCBNext和*OSTCBPrev連成一個(gè)可用任務(wù)雙向鏈表,并將指針OSTCBFreeList指向第一個(gè)TCB。以后每當(dāng)一個(gè)任務(wù)創(chuàng)建時(shí),就根據(jù)OSTCBFreeList從可用任務(wù)雙向鏈表獲取一個(gè)TCB同時(shí)將OSTCBFreeList指向下一個(gè)TCB,如圖4.3所示。
uC/OS是剝奪型實(shí)時(shí)多任務(wù)內(nèi)核,優(yōu)先級(jí)最高的任務(wù)一旦準(zhǔn)備就緒,則擁有CPU的所有權(quán)開(kāi)始投入運(yùn)行。uC/OS中不支持時(shí)間片輪轉(zhuǎn)法,每個(gè)任務(wù)的優(yōu)先級(jí)要求不一樣且是唯一的,所以任務(wù)調(diào)度的工作就是:查找準(zhǔn)備就緒的最高優(yōu)先級(jí)的任務(wù)并進(jìn)行上下文切換。函數(shù)OSSched(void)進(jìn)行任務(wù)調(diào)度。其程序結(jié)構(gòu)如下(程序4.2)。 如果某個(gè)任務(wù)在某段代碼的執(zhí)行期間不能被其他任務(wù)所搶占,可以調(diào)用OSSchedlock( )函數(shù)來(lái)給調(diào)度器上鎖以禁止調(diào)度,之后再調(diào)用OSSchedUnlock( )開(kāi)鎖允許調(diào)度。例如低優(yōu)先級(jí)的任務(wù)要發(fā)給其他任務(wù)郵箱、消息隊(duì)列時(shí),用戶不希望高優(yōu)先級(jí)的任務(wù)還沒(méi)有得到消息就取得了CPU的使用權(quán),就可以使用OSSchedlock( )。
程序4.2 任務(wù)調(diào)度原理 ------------------------------------------------------------
如前所述,uC/OS是通過(guò)查表法找到準(zhǔn)備就緒的優(yōu)先級(jí)最高的任務(wù),下面將說(shuō)明查表的過(guò)程。為了實(shí)現(xiàn)就緒任務(wù)的快速查找,uC/OS采用了一種奇特的方式。既然uC/OS中每一個(gè)任務(wù)的優(yōu)先級(jí)是唯一的,不存在相同優(yōu)先級(jí)的兩個(gè)任務(wù),所以可以根據(jù)優(yōu)先級(jí)來(lái)唯一的確定任務(wù)。uC/OS支持64個(gè)任務(wù),也就是由64個(gè)優(yōu)先級(jí)0-63,二進(jìn)制中可以用6位來(lái)表示,然后根據(jù)高三位將64個(gè)任務(wù)分為8個(gè)準(zhǔn)備就緒表數(shù)組OSRdyTbl[7],每組又根據(jù)低3位包含8個(gè)任務(wù),若每組有任務(wù)處于就緒態(tài),則相應(yīng)的比特置1;假設(shè)任務(wù)3和任務(wù)5處于就緒態(tài),則OSRdyTbl[0]=0x28;任務(wù)17和任務(wù)20處于就緒態(tài),則OSRdyTbl[2]=0x12。 uC/OS還定義了一個(gè)8比特字節(jié)變量,OSRdyGrp準(zhǔn)備就緒組。OSRdyGrp中的每一位表示8組任務(wù)中每一組是否有準(zhǔn)備就緒的任務(wù),其相互關(guān)系見(jiàn)下(圖4.4)。
圖4.4 uC/OS任務(wù)查表原理
假設(shè)優(yōu)先級(jí)為12的任務(wù)進(jìn)入就緒狀態(tài),12=1 100b,則OSRdyTbl[1]的第4位置1,且OSRdyGrp的第1位置1,相應(yīng)的數(shù)學(xué)表達(dá)式為:
OSRdyGrp |=0x02; OSRdyTbl[1] |=0x10;
而優(yōu)先級(jí)為21的任務(wù)就緒21=10 101b,則OSRdyTbl[2]的第5位置1,且OSRdyGrp的第2位置1,相應(yīng)的數(shù)學(xué)表達(dá)式為:
OSRdyGrp |=0x04; OSRdyTbl[2] |=0x20;
從上面的計(jì)算我們可以得到:若第n位置1,則應(yīng)該與2n 相或。uC/OS中,把2n的n=0-7的8個(gè)值 先計(jì)算好存在數(shù)組OSMapTbl[7]中,也就是: OSMapTbl[0] =20=0x1; OSMapTbl[1] =21=0x2;
OSMapTbl[7] =27=0x80;
利用OSMapTbl,通過(guò)任務(wù)的識(shí)別號(hào)-優(yōu)先級(jí)prio來(lái)設(shè)置任務(wù)在就緒組和就緒表數(shù)組中相應(yīng)位置的數(shù)學(xué)式為: OSRdyGrp |=OSMapTbl[prio>>3]; OSRdyTbl[prio>>3] |=OSMapTbl[prio & 0x07]; 因?yàn)?4個(gè)優(yōu)先級(jí)可用6位來(lái)表示,所以高三位可用prio>>3得到,低三位通過(guò)prio & 0x07獲得。但我一直存在這樣的疑問(wèn):2n運(yùn)算只需通過(guò)簡(jiǎn)單的移位即可獲得,通過(guò)查表來(lái)獲得能夠真正節(jié)約時(shí)間嗎?
下面我們說(shuō)明如何利用就緒組和就緒表數(shù)組來(lái)獲得優(yōu)先級(jí)最高的就緒任務(wù)識(shí)別號(hào)即優(yōu)先級(jí)數(shù)。前面我們把優(yōu)先級(jí)數(shù)分解為高三位和低三位,從而決定任務(wù)在就緒組和就緒表數(shù)組中相應(yīng)位置,這里我們先想辦法先分別求出高三位和低三位即可。假設(shè)OSRdyGrp值為0x24=100 100b,表明OSRdyTbl[2]和OSRdyTbl[5]存在準(zhǔn)備就緒的任務(wù),根據(jù)圖4.4,顯然OSRdyTbl[2]中的任務(wù)優(yōu)先級(jí)比OSRdyTbl[5]要高,所以最高優(yōu)先級(jí)就緒任務(wù)的高3位一定是2;再通過(guò)OSRdyTbl[2]的值來(lái)確定低3位,假設(shè)為0x12=010 010b,表明第1個(gè)和第4個(gè)任務(wù)處于就緒態(tài),優(yōu)先級(jí)高的任務(wù)是第1個(gè),所以最高優(yōu)先級(jí)就緒任務(wù)的低3位一定是1;最后可以得到最高優(yōu)先級(jí)的就緒任務(wù)的優(yōu)先級(jí)為010 010b=18。
上面我們通過(guò)觀察法利用OSRdyGrp和OSRdyTbl值求出最高優(yōu)先級(jí)的就緒任務(wù)的優(yōu)先級(jí),接下來(lái)推導(dǎo)一般方法。推導(dǎo)的關(guān)鍵在于這個(gè)事實(shí):高優(yōu)先級(jí)有著最小的優(yōu)先級(jí)號(hào),所以不管對(duì)于求高3位還是低3位,都是將已知的數(shù)展開(kāi)成8位的二進(jìn)制數(shù),最低為1的位數(shù)即為相應(yīng)的欲獲得的數(shù),即:
1=00000001b->0 (最低為1的位是第0位), 2=00000010b->1 (最低為1的位是第1位), 3=00000011b->0 (最低為1的位是第1位),
可以用算法這樣實(shí)現(xiàn):令n=0,將已知數(shù)與2n相與,若不為0,則n即為所求,否則n++,進(jìn)行下一個(gè)循環(huán)。程序結(jié)構(gòu)如下(程序4.3):
程序4.3 查找最高優(yōu)先級(jí)的算法 --------------------------------------------------------------------------- n=0; do { if (OSRdyGrp & 2n) break; n++; } while(n<8) 利用上述程序,
(1 & 20)=1, 最低為1的位是第0位; (2 & 21)=1, 最低為1的位是第1位; (3 & 20)=1, 最低為1的位是第0位;
顯然,用程序?qū)崿F(xiàn)不但復(fù)雜,更重要的是執(zhí)行時(shí)間是不確定的,因?yàn)橛袝r(shí)只需一個(gè)循環(huán)即可,而有時(shí)需要8個(gè)循環(huán),不符合實(shí)時(shí)系統(tǒng)的確定性原則。所以在uC/OS中,仍然采用查表的方法實(shí)現(xiàn),這個(gè)表為數(shù)組OSUnMapTbl[255],利用該表,計(jì)算最高優(yōu)先級(jí)任務(wù)的優(yōu)先級(jí)的算法如下:
程序4.4 計(jì)算最高優(yōu)先級(jí)任務(wù)的優(yōu)先級(jí)的算法 ------------------------------------------------------------ High3 =OSUnMapTbl[OSRdyGrp]; Low3 =OSUnMapTbl[OSRdyTbl][High3]]; Prio =(Hign3<<3)+Low3; 至此,我們已經(jīng)把uC/OS任務(wù)調(diào)度機(jī)制較為詳細(xì)分析了一遍;
|