μC/OS-II的任務(wù)管理
這樣,OSTaskDel()就能處理中斷服務(wù)了,但由于它增加了 OSLockNesting,ISR執(zhí)行完后會返回到被中斷任務(wù),從而繼續(xù)任務(wù)的刪除工作。注意OSTaskDel()此時還沒有完全完成刪除任務(wù)的工作,因?yàn)樗€需要從TCB鏈中解開OS_TCB,并將OS_TCB返回到空閑OS_TCB表中。
另外需要注意的是,筆者在調(diào)用OS_EXIT_CRITICAL()函數(shù)后,馬上調(diào)用了OSDummy()[L4.11(12)],該函數(shù)并不會進(jìn)行任何實(shí)質(zhì)性的工作。這樣做只是因?yàn)橄氪_保處理器在中斷允許的情況下至少執(zhí)行一個指令。對于許多處理器來說,執(zhí)行中斷允許指令會強(qiáng)制CPU禁止中斷直到下個指令結(jié)束!Intel80x86和ZilogZ-80處理器就是如此工作的。開中斷后馬上關(guān)中斷就等于從來沒開過中斷,當(dāng)然這會增加中斷的響應(yīng)時間。因此調(diào)用OSDummy()確保在再次禁止中斷之前至少執(zhí)行了一個調(diào)用指令和一個返回指令。當(dāng)然,用戶可以用宏定義將OSDummy()定義為一個空操作指令(譯者注:例如MC68HC08指令中的NOP指令) ,這樣調(diào)用OSDummy()就等于執(zhí)行了一個空操作指令,會使OSTaskDel()的執(zhí)行時間稍微縮短一點(diǎn)。但筆者認(rèn)為這種宏定義是沒價值的,因?yàn)樗鼤黾右浦?mu;COS-Ⅱ的工作量。
現(xiàn)在,OSTaskDel()可以繼續(xù)執(zhí)行刪除任務(wù)的操作了。在OSTaskDel()重新關(guān)中斷后,它通過鎖定嵌套計(jì)數(shù)器(OSLockNesting)減一以重新允許任務(wù)調(diào)度[L4.11(13)]。接著,OSTaskDel()調(diào)用用戶自定義的OSTaskDelHook()函數(shù)[L4.11(14)],用戶可以在這里刪除或
釋放自定義的TCB附加數(shù)據(jù)域。 然后, OSTaskDel()減少μCOS-Ⅱ的任務(wù)計(jì)數(shù)器。 OSTaskDel()
簡單地將指向被刪除的任務(wù)的OS_TCB的指針指向NULL[L4.11(15)],從而達(dá)到將OS_TCB從優(yōu)先級表中移除的目的。再接著,OSTaskDel()將被刪除的任務(wù)的OS_TCB從OS_TCB雙向鏈表中移除[L4.11(16)]。 注意,沒有必要檢驗(yàn)ptcb->OSTCBNext==0的情況, 因?yàn)镺STaskDel()不能刪除空閑任務(wù),而空閑任務(wù)就處于鏈表的末端(ptcb->OSTCBNext==0)。接下來,OS_TCB返回到空閑OS_TCB表中,并允許其它任務(wù)的建立[L4.11(17)]。最后,調(diào)用任務(wù)調(diào)度程序來查看在OSTaskDel()重新允許中斷的時候[L4.11(11)],中斷服務(wù)子程序是否曾使更高優(yōu)先級的任務(wù)處于就緒狀態(tài)[L4.11(18)]。
4.5請求刪除任務(wù),OSTaskDelReq()
有時候,如果任務(wù)A擁有內(nèi)存緩沖區(qū)或信號量之類的資源,而任務(wù)B想刪除該任務(wù),這些資源就可能由于沒被釋放而丟失。在這種情況下,用戶可以想法子讓擁有這些資源的任務(wù)在使用完資源后,先釋放資源,再刪除自己。用戶可以通過OSTaskDelReq()函數(shù)來完成該功能。
發(fā)出刪除任務(wù)請求的任務(wù)(任務(wù)B)和要刪除的任務(wù)(任務(wù)A)都需要調(diào)用OSTaskDelReq()函數(shù)。任務(wù)B的代碼如程序清單L4.12所示。任務(wù)B需要決定在怎樣的情況下請求刪除任務(wù)[L4.12(1)]。換句話說,用戶的應(yīng)用程序需要決定在什么樣的情況下刪除任務(wù)。如果任務(wù)需要被刪除,可以通過傳遞被刪除任務(wù)的優(yōu)先級來調(diào)用OSTaskDelReq()[L4.12(2)]。如果要被刪除的任務(wù)不存在(即任務(wù)已被刪除或是還沒被建立),OSTaskDelReq()返回OS_TASK_NOT_EXIST。如果OSTaskDelReq()的返回值為OS_NO_ERR,則表明請求已被接受但任務(wù)還沒被刪除。用戶可能希望任務(wù)B等到任務(wù)A刪除了自己以后才繼續(xù)進(jìn)行下面的工作,這時用戶可以象筆者一樣,通過讓任務(wù)B延時一定時間來達(dá)到這個目的[L4.12(3)]。筆者延時了一個時鐘節(jié)拍。如果需要,用戶可以延時得更長一些。當(dāng)任務(wù)A完全刪除自己后,[L4.12(2)]中的返回值成為0S_TASK_NOT_EXIST,此時循環(huán)結(jié)束[L4.12(4)]。
程序清單 L4.12 請求刪除其它任務(wù)的任務(wù)(任務(wù)B)
voidRequestorTask(void*pdata)
{
INT8Uerr;
pdata=pdata;
for(;;){
/* 應(yīng)用程序代碼 */
if('TaskToBeDeleted()' 需要被刪除){(1)
while(OSTaskDelReq(TASK_TO_DEL_PRIO)!=OS_TASK_NOT_EXIST){(2)
OSTimeDly(1);(3)
}
}
/*應(yīng)用程序代碼*/(4)
}
}
程序清單 L4.13 需要刪除自己的任務(wù)(任務(wù)A)
voIDTaskToBeDeleted(void*pdata)
{
INT8Uerr;
pdata=pdata;
for(;;){
/*應(yīng)用程序代碼*/
If(OSTaskDelReq(OS_PRIO_SELF)==OS_TASK_DEL_REQ){(1)
釋放所有占用的資源;(2)
釋放所有動態(tài)內(nèi)存;
OSTaskDel(OS_PRIO_SELF);(3)
}else{
/*應(yīng)用程序代碼*/
}
}
}
需要刪除自己的任務(wù)(任務(wù)A)的代碼如程序清單L4.13所示。在OS_TAB中存有一個標(biāo)志,任務(wù)通過查詢這個標(biāo)志的值來確認(rèn)自己是否需要被刪除。這個標(biāo)志的值是通過調(diào)用OSTaskDelReq(OS_PRIO_SELF)而得到的。當(dāng)OSTaskDelReq()返回給調(diào)用者OS_TASK_DEL_REQ[L4.13(1)]時,則表明已經(jīng)有另外的任務(wù)請求該任務(wù)被刪除了。在這種情況下,被刪除的任務(wù)會釋放它所擁有的所用資源[L4.13(2)],并且調(diào)用OSTaskDel(OS_PRIO_SELF)來刪除自己[L4.13(3)]。前面曾提到過,任務(wù)的代碼沒有被真正的刪除,而只是μC/OS-Ⅱ不再理會該任務(wù)代碼,換句話說,就是任務(wù)的代碼不會再運(yùn)行了。
但是,用戶可以通過調(diào)用OSTaskCreate()或OSTaskCreateExt()函數(shù)重新建立該任務(wù)。OSTaskDelReq()的代碼如程序清單L4.14所示。通常OSTaskDelReq()需要檢查臨界條件。首先,如果正在刪除的任務(wù)是空閑任務(wù),OSTaskDelReq()會報(bào)錯并返回[L4.14(1)]。接著,它要保證調(diào)用者請求刪除的任務(wù)的優(yōu)先級是有效的[L4.14(2)]。如果調(diào)用者就是被刪除任務(wù)本身,存儲在OS_TCB中的標(biāo)志將會作為返回值[L4.14(3)]。如果用戶用優(yōu)先級而不是OS_PRIO_SELF指定任務(wù),并且任務(wù)是存在的[L4.14(4)],OSTaskDelReq()就會設(shè)置任務(wù)的內(nèi)部標(biāo)志[L4.14(5)]。如果任務(wù)不存在,OSTaskDelReq()則會返回OS_TASK_NOT_EXIST,表明任務(wù)可能已經(jīng)刪除自己了[L4.14(6)]。
程序清單 L4.14 OSTaskDelReq().
INT8UOSTaskDelReq(INT8Uprio)
{
BOOLEANstat;
INT8Uerr;
OS_TCB*ptcb;
if(prio==OS_IDLE_PRIO){(1)
return(OS_TASK_DEL_IDLE);
}
if(prio>=OS_LOWEST_PRIOprio!=OS_PRIO_SELF){
評論