FreeRTOS之任務建立刪除
阿新 • • 發佈:2019-01-09
tskTCB結構的定義這裡就不再給出來了,需要注意的是其中uxBasePriority元素,它用於解決優先順序反轉,freertos採用優先順序繼承的辦法解決這個問題,在繼承時,將任務原先的優先順序儲存在這個成員中,將來再從這裡恢復任務的優先順序。
兩個延時連結串列的正解:freertos弄出兩個延時連結串列是因為它的延時任務管理的需要。freertos根據任務延時時間的長短按序將任務插入這兩個連結串列之一。在插入前先把任務將要延時的xTicksToDelay數加上系統當前tick數,這樣得到了一個任務延時due
time(到期時間)的絕對數值。但是有可能這個相加操作會導致溢位,如果溢位則加入到 pxOverflowDelayedTaskList指向的那個連結串列,否則加入pxDelayedTaskList指向的連結串列。
xPendingReadyList;這個連結串列用在排程器被lock(就是禁止排程了)的時期,如果一個任務從非就緒狀態變為就緒狀態,它不直接加到就緒連結串列中,而是加到這個pending連結串列中。等排程器重新啟動(unlock)的時候再檢查這個連結串列,把裡面的任務加到就緒連結串列中。
任務管理:
freertos與ucosii不同,它的任務控制塊並不是靜態分配的,而是在建立任務的時候動態分配。另外,freertos的優先順序是優先順序數越大優先順序越高,和ucosii 正好相反。任務控制塊中也沒有任務狀態的成員變數,這是因為freertos中的任務總是根據他們的狀態連入對應的連結串列,沒有必要在任務控制塊中維護一個狀態。此外freertos對任務的數量沒有限制,而且同一個優先順序可以有多個任務。
任務刪除:
任務建立過程前面講過了,這裡就直接看任務刪除的工程。freertos的任務刪除分兩步完成,第一步在vTaskDelete中完成,FreeRTOS先把要刪除的任務從就緒任務連結串列和事件等待連結串列中刪除,然後把此任務新增到任務刪除連結串列(即那個xTasksWaitingTermination),若刪除的任務是當前執行任務,系統就執行任務排程函式.第2 步則是在idle任務中完成,idle任務執行時,檢查xTasksWaitingTermination連結串列,如果有任務在這個表上,釋放該任務佔用的記憶體空間,並把該任務從任務刪除連結串列中刪除。
/****************************************************************
**引數:pxTaskToDelete是一個指向被刪除任務的控制代碼,這裡其實就是等價於任務控制塊
**如果這個控制代碼==NULL,則表示要刪除當前任務
*******************************************************************/
void vTaskDelete( xTaskHandle pxTaskToDelete )
{
tskTCB *pxTCB;
taskENTER_CRITICAL();
{
/* 如果刪除的是當前任務,則刪除完成後需要進行排程*/
if( pxTaskToDelete == pxCurrentTCB )
{
pxTaskToDelete = NULL;
}
/*通過傳進來的任務控制代碼得到對應的tcb*/
pxTCB = prvGetTCBFromHandle( pxTaskToDelete );
traceTASK_DELETE( pxTCB );
/* 把任務從就緒連結串列或者延時連結串列或者掛起連結串列中刪除*/
vListRemove( &( pxTCB->xGenericListItem ) );
/* 判斷任務是否在等待事件(semaphore訊息佇列等) */
if( pxTCB->xEventListItem.pvContainer )
{//如果是,則把它從事件等待連結串列中刪除
vListRemove( &( pxTCB->xEventListItem ) );
}
//插入等待刪除連結串列
vListInsertEnd( ( xList * ) &xTasksWaitingTermination, &( pxTCB->xGenericListItem ) );
//增加uxTasksDeleted計數
++uxTasksDeleted;
}
taskEXIT_CRITICAL();
/*如果排程器已經執行,並且刪除的是當前任務,則排程*/
if( xSchedulerRunning != pdFALSE )
{
if( ( void * ) pxTaskToDelete == NULL )
{
taskYIELD();
}
}
}
再看空閒任務做的第2步工作:
static portTASK_FUNCTION( prvIdleTask, pvParameters )
{
/* Stop warnings. */
( void ) pvParameters;
for( ;; )
{
/* See if any tasks have been deleted. */
prvCheckTasksWaitingTermination();
…………………………….÷
* The portTASK_FUNCTION() macro is used to allow port/compiler specific
* language extensions.The equivalent prototype for this function is:
* void prvIdleTask( void *pvParameters );
這裡prvCheckTasksWaitingTermination()就是幹這第2步的工作:每次呼叫它刪除一個任務
static void prvCheckTasksWaitingTermination( void )
{
#if ( INCLUDE_vTaskDelete == 1 )
{
portBASE_TYPE xListIsEmpty;
/* ucTasksDeleted is used to prevent vTaskSuspendAll() being called
too often in the idle task. */
if( uxTasksDeleted > ( unsigned portBASE_TYPE ) 0 )
{//禁止排程
vTaskSuspendAll();
//開啟排程
xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );
xTaskResumeAll();
if( !xListIsEmpty )
{
tskTCB *pxTCB;
//關中斷
portENTER_CRITICAL();
{
pxTCB = ( tskTCB * ) listGET_OWNER_OF_HEAD_ENTRY( ( ( xList * ) &xTasksWaitingTermination ) );
vListRemove( &( pxTCB->xGenericListItem ) );
--uxCurrentNumberOfTasks;
--uxTasksDeleted;
}
portEXIT_CRITICAL();
//釋放記憶體,刪除tcb
prvDeleteTCB( pxTCB );
}
}
}
#endif
}