1. 程式人生 > >FreeRTOS之任務建立刪除

FreeRTOS之任務建立刪除

tskTCB結構的定義這裡就不再給出來了,需要注意的是其中uxBasePriority元素,它用於解決優先順序反轉,freertos採用優先順序繼承的辦法解決這個問題,在繼承時,將任務原先的優先順序儲存在這個成員中,將來再從這裡恢復任務的優先順序。 兩個延時連結串列的正解freertos弄出兩個延時連結串列是因為它的延時任務管理的需要。freertos根據任務延時時間的長短按序將任務插入這兩個連結串列之一。在插入前先把任務將要延時的xTicksToDelay數加上系統當前tick數,這樣得到了一個任務延時due time(到期時間)的絕對數值。但是有可能這個相加操作會導致溢位,如果溢位則加入到
pxOverflowDelayedTaskList指向的那個連結串列,否則加入pxDelayedTaskList指向的連結串列。 xPendingReadyList;這個連結串列用在排程器被lock(就是禁止排程了)的時期,如果一個任務從非就緒狀態變為就緒狀態,它不直接加到就緒連結串列中,而是加到這個pending連結串列中等排程器重新啟動(unlock)的時候再檢查這個連結串列,把裡面的任務加到就緒連結串列中 任務管理: freertosucosii不同,它的任務控制塊並不是靜態分配的,而是在建立任務的時候動態分配。另外,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