?? chapter4.txt
字號:
4.00 Creating a Task, OSTaskCreate()
只想說一處:
OS_ENTER_CRITICAL();
if(OSTCBPrioTbl[prio] == (OS_TCB *)0){
OSTCBPrioTbl[prio] = (OS_TCB *)1;
OS_EXIT_CRITICAL();
....
這里的OSTCBPrioTbl[prio] = (OS_TCB *)1;一句僅僅是為了盡快將OSTCBPrioTbl[prio]填充為一個非0的值,以表示該優先級已經被使用了,從而防止其他任務也使用這一優先級。但為什么要用(OS_TCB *)1而不是TCB的實際指針值呢?這是因為,如果要使用TCB實際的指針值,需要依次調用OSTaskStkInit和OSTCBInit兩個函數。這兩個函數都是很花時間的,如果在禁止中斷的情況下使用它們,勢必會造成很高的中斷延時。為了能夠盡早地使程序能夠恢復中斷同時又保證當前使用優先級不被其他任務使用,作者在這里使用(OS_TCB *)1作為標志。在將OSTCBPrioTbl[prio]項填寫為(OS_TCB *)1后即可恢復中斷,而同時因為OSTCBPrioTbl[prio]的值已不再為(OS_TCB *)0,故其他任務也無法使用該優先級,一舉兩得。
4.02 Task Staks
對Task Stack的建立有兩種方式:靜態方式和動態方式。
靜態方式實際上就是將Task Stack聲明為全局變量。這樣在程序編譯時,就將空間分配好了,而且該空間不會被回收,知道程序運行結束。
動態方式可以使用C語言中的malloc函數在程序運行時對地址空間進行分配,而在該空間不再需要時,使用free將其回收。
從以上討論來看,貌似使用動態方式要優越許多,其實也不盡然。動態方式可能會造成內存碎片,從而影響內存的進一步使用。而且,如果程序中存在任務需要多次建立刪除,建議使用靜態方式為其申請堆棧空間。因為若使用動態方式的話,需要反復為該任務分配和回收內存空間,增加系統的開銷。
4.04 Deleting a Task, OSTaskDel()
刪除一個任務需要以下步驟:
1、對輸入的優先級進行例行的界限檢查;
2、將任務從就緒隊列中移除,同時如果任務在等待某事件將其從等待隊列中移除;
3、將任務PCB中的OSTCBDly項賦值為0,防止任務被時間中斷處理函數OSTimeTick重新加入就緒隊列;
4、將任務PCB中的OSTCBStat項賦值為OS_STAT_RDY,防止任務被其他函數(如:OSTaskResume)重新加入就緒隊列;
5、至此為止,如果任務被切換的話,它將無法被再次調回,但此時對任務的刪除操作尚未完成需要繼續。不過,惱火的是,如果繼續在關閉中斷的情況下操作勢必會造成很大的中斷延時。為了減少中斷延時同時保證任務不被切換,在恢復中斷前,需要關閉任務調度。這項操作不需要太長的時間,只需要被延時的中斷能夠保證響應就可以了。因此,這里作者引入了一個空函數OSdummy,執行此函數僅僅是為了提供幾個指令周期的時間供被延時的中斷響應;
6、進行一些善后的處理包括減少OSTaskCtr的值、將任務使用的優先級釋放以及將任務TCB從當前使用TCB鏈表中移除并加入空閑PCB鏈表中;
7、調用OSShed函數。
4.05 Requesting to delete a task, OSTaskDelReq()
如果一個任務在執行中會控制某些資源,那么在刪除該任務時,需要首先將這些資源釋放。
為了達到以上目的,需要刪除操作的請求者與被刪除任務中都引入對OSTaskDelReq函數的呼叫。兩類任務的具體代碼流程如下:
刪除操作的請求者:
void RequestorTask (void *pdata)
{
INT8U err;
pdata = pdata;
for (;;) {
/* Application code */
if (‘TaskToBeDeleted()’ needs to be deleted) {
while (OSTaskDelReq(TASK_TO_DEL_PRIO) != OS_TASK_NOT_EXIST) {
OSTimeDly(1);
}
}
/* Application code */
}
}
待刪除任務:
void TaskToBeDeleted (void *pdata)
{
INT8U err;
pdata = pdata;
for (;;) {
/* Application code */
if (OSTaskDelReq(OS_PRIO_SELF) == OS_TASK_DEL_REQ) {
Release any owned resources;
De-allocate any dynamic memory;
OSTaskDel(OS_PRIO_SELF);
} else {
/* Application code */
}
}
}
具體原理如下:
在任務的TCB中設有一名為OSTCBDelReq的變量,此變量在任務建立時被初始化為OS_NO_ERR。同時,對于OSTaskDelReq函數,如果輸入參數為OS_PRIO_SELF則只返回當前任務TCB中OSTCBDelReq的值;而如果輸入參數是一個有效的優先級值,則判斷具有此優先級的任務是否存在,若存在將該任務的OSTCBDelReq項賦值為OS_TASK_DEL_REQ并返回OS_NO_ERR,否則返回OS_TASK_NOT_EXIST。
根據以上討論,在RequestorTask函數尚未呼叫OSTaskDelReq(TASK_TO_DEL_PRIO)時,待刪除任務中OSTaskDelReq(OS_PRIO_SELF)的返回值為OS_NO_ERR,因此其執行else中的代碼進行正常的操作。而一旦RequestorTask呼叫了OSTaskDelReq(TASK_TO_DEL_PRIO),待刪除任務TCB中的OSTCBDelReq被賦值為OS_TASK_DEL_REQ,因此當再次執行TaskToBeDeleted時,將執行if內的語句,即釋放資源刪除自己。
經過上述討論,可以發現,這里OSTCBDelReq實際相當于一個郵箱的角色用于RequestorTask 與TaskToBeDeleted 之間的通信。
另外,需要說明的是,實際上也可以由待刪除任務通過調用OSTaskDelReq函數完成對自己的刪除。
在這種情況下,僅需要一個任務函數即TaskToBeDeleted ,但其代碼結構需要做一定的調整:
void TaskToBeDeleted (void *pdata)
{
INT8U err;
pdata = pdata;
for (;;) {
/* Application code */
if (OSTaskDelReq(OS_PRIO_SELF) == OS_TASK_DEL_REQ) {
Release any owned resources;
De-allocate any dynamic memory;
OSTaskDel(OS_PRIO_SELF);
} else {
/* Application code */
if (‘TaskToBeDeleted()’ needs to be deleted){
while (OSTaskDelReq(PRIO_OF_CUR_TASK) != OS_TASK_NOT_EXIST) {
OSTimeDly(1);
}
}
/* Application code */
}
}
}
最后,建議一點,這種形式的任務刪除主要用于需要掌握某些資源的任務。對于一般任務,使用此種結構也可以正常完成目標,不過這相當于將簡單的問題復雜化了,因此對于一般的任務的刪除操作還是使用普通的代碼結構要好一些。
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -