μC/OS-II的任務管理
}else{
OSTCBPrioTbl[newprio]=(OS_TCB*)0;(17)
OS_EXIT_CRITICAL();
return(OS_PRIO_ERR);
}
}
}
4.7 掛起任務,OSTaskSuspend()
有時候將任務掛起是很有用的。掛起任務可通過調用OSTaskSuspend()函數來完成。被掛起的任務只能通過調用OSTaskResume()函數來恢復。任務掛起是一個附加功能。也就是說,如果任務在被掛起的同時也在等待延時的期滿,那么,掛起操作需要被取消,而任務繼續等待延時期滿,并轉入就緒狀態。任務可以掛起自己或者其它任務。
OSTaskSuspend()函數的代碼如程序清單L4.16所示。通常OSTaskSuspend()需要檢驗臨界條件。首先,OSTaskSuspend()要確保用戶的應用程序不是在掛起空閑任務[L4.16(1)],接著確認用戶指定優先級是有效的[L4.16(2)]。記住最大的有效的優先級數(即最低的優先級)是OS_LOWEST_PRIO。注意,用戶可以掛起統計任務(statistic) 。可能用戶已經注意到了,第一個測試[L4.16(1)]在[L4.16(2)]中被重復了。筆者這樣做是為了能與μC/OS兼容。
第一個測試能夠被移除并可以節省一點程序處理的時間,但是,這樣做的意義不大,所以筆者決定留下它。
接著, OSTaskSuspend()檢驗用戶是否通過指定 OS_PRIO_SELF來掛起調用本函數的任務本身[L4.16(3)]。用戶也可以通過指定優先級來掛起調用本函數的任務[L4.16(4)]。在這兩種情況下,任務調度程序都需要被調用。這就是筆者為什么要定義局部變量self的原因,該變量在適當的情況下會被測試。如果用戶沒有掛起調用本函數的任務,OSTaskSuspend()就沒有必要運行任務調度程序,因為正在掛起的是較低優先級的任務。
然后,OSTaskSuspend()檢驗要掛起的任務是否存在[L4.16(5)]。如果該任務存在的話,它就會從就緒表中被移除[L4.16(6)]。注意要被掛起的任務有可能沒有在就緒表中,因為它有可能在等待事件的發生或延時的期滿。在這種情況下,要被掛起的任務在OSRdyTbl[]中對應的位已被清除了(即為0)。再次清除該位,要比先檢驗該位是否被清除了再在它沒被清除時清除它快得多,所以筆者沒有檢驗該位而直接清除它。現在,OSTaskSuspend()就可以在任務的OS_TCB中設置OS_STAT_SUSPEND標志了,以表明任務正在被掛起[L4.16(7)]。最后,OSTaskSuspend()只有在被掛起的任務是調用本函數的任務本身的情況下才調用任務調度程序[L4.16(8)]。
程序清單 L4.16 OSTaskSuspend().
INT8UOSTaskSuspend(INT8Uprio)
{
BOOLEANself;
OS_TCB*ptcb;
if(prio==OS_IDLE_PRIO){(1)
return(OS_TASK_SUSPEND_IDLE);
}
if(prio>=OS_LOWEST_PRIOprio!=OS_PRIO_SELF){
(2)
return(OS_PRIO_INVALID);
}
OS_ENTER_CRITICAL();
if(prio==OS_PRIO_SELF){(3)
prio=OSTCBCur->OSTCBPrio;
self=TRUE;
}elseif(prio==OSTCBCur->OSTCBPrio){(4)
self=TRUE;
}else{
self=FALSE;
}
if((ptcb=OSTCBPrioTbl[prio])==(OS_TCB*)0){(5)
OS_EXIT_CRITICAL();
return(OS_TASK_SUSPEND_PRIO);
}else{
if((OSRdyTbl[ptcb->OSTCBY]=~ptcb->OSTCBBitX)==0){(6)
OSRdyGrp=~ptcb->OSTCBBitY;
}
ptcb->OSTCBStat|=OS_STAT_SUSPEND;(7)
OS_EXIT_CRITICAL();
if(self==TRUE){(8)
OSSched();
}
return(OS_NO_ERR);
}
}
4.8 恢復任務,OSTaskResume()
在上一節中曾提到過,被掛起的任務只有通過調用OSTaskResume()才能恢復。OSTaskResume()函數的代碼如程序清單L4.17所示。 因為OSTaskSuspend()不能掛起空閑任務,所以必須得確認用戶的應用程序不是在恢復空閑任務[L4.17(1)]。注意,這個測試也可以確保用戶不是在恢復優先級為OS_PRIO_SELF的任務(OS_PRIO_SELF被定義為0xFF,它總是比OS_LOWEST_PRIO大)。
要恢復的任務必須是存在的,因為用戶要需要操作它的任務控制塊OS_TCB[L4.17(2)],并且該任務必須是被掛起的[L4.17(3)]。OSTaskResume()是通過清除OSTCBStat域中的OS_STAT_SUSPEND位來取消掛起的[L4.17(4)]。要使任務處于就緒狀態,OS_TCBDly域必須為0[L4.17(5)],這是因為在OSTCBStat中沒有任何標志表明任務正在等待延時的期滿。只有當以上兩個條件都滿足的時候,任務才處于就緒狀態[L4.17(6)]。最后,任務調度程序會檢查被恢復的任務擁有的優先級是否比調用本函數的任務的優先級高[L4.17(7)]。
程序清單 L4.17 OSTaskResume().
INT8UOSTaskResume(INT8Uprio)
{
OS_TCB*ptcb;
If(prio>=OS_LOWEST_PRIO){(1)
return(OS_PRIO_INVALID);
}
OS_ENTER_CRITICAL();
If((ptcb=OSTCBPrioTbl[prio])==(OS_TCB*)0){(2)
OS_EXIT_CRITICAL();
return(OS_TASK_RESUME_PRIO);
}else{
if(ptcb->OSTCBStatOS_STAT_SUSPEND){(3)
if(((ptcb->OSTCBStat=~OS_STAT_SUSPEND)==OS_STAT_RDY)(4)
(ptcb->OSTCBDly==0)){(5)
OSRdyGrp|=ptcb->OSTCBBitY;(6)
OSRdyTbl[ptcb->OSTCBY]|=ptcb->OSTCBBitX;
OS_EXIT_CRITICAL();
OSSched();(7)
}else{
OS_EXIT_CRITICAL();
}
return(OS_NO_ERR);
}else{
OS_EXIT_CRITICAL();
return(OS_TASK_NOT_SUSPENDED);
}
}
}
4.9 獲得有關任務的信息,OSTaskQuery()
用戶的應用程序可以通過調用OSTaskQuery()來獲得自身或其它應用任務的信息。實際上,OSTaskQuery()獲得的是對應任務的 OS_TCB中內容的拷貝。用戶能訪問的OS_TCB的數據域的多少決定于用戶的應用程序的配置(參看OS_CFG.H)。由于μC/OS-Ⅱ是可裁剪的,它只包括那些用戶的應用程序所要求的屬性和功能。












評論