FreeRTOS學習記錄----任務刪除、掛起、恢復函數詳解


(一)任務刪除函數詳解

  vTaskDelete()函數用於刪除一個任務,形參為要刪除任務的任務句柄,如果刪除自身,那么參數為NULL。要想使用該函數,必須將宏INCLUDE_vTaskDelete定義為1;要刪除的任務就是把任務從所有就緒列表,阻塞列表,掛起列表中刪除。

直接上代碼!

void vTaskDelete( TaskHandle_t xTaskToDelete ){
    TCB_t *pxTCB;
    taskENTER_CRITICAL();
    {
        /* 獲取要刪除任務的任務控制塊,參數是任務句柄,如果參數為當前正在執行的任務句柄,那么返回值為null */
        pxTCB = prvGetTCBFromHandle( xTaskToDelete );
        /* 將任務從就緒列表中刪除 */
        if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ){
            taskRESET_READY_PRIORITY( pxTCB->uxPriority );
        }
        else{
            mtCOVERAGE_TEST_MARKER();
        }
        /* 查看任務是否在等待某個事件信號量,隊列等,並將其從相應的列中刪除 */
        if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ){
            ( void ) uxListRemove( &( pxTCB->xEventListItem ) );
        }
        else{
            mtCOVERAGE_TEST_MARKER();
        }
            
        uxTaskNumber++;
        /* 如果要刪除的是當前正在運行的任務 */
        if( pxTCB == pxCurrentTCB ){
            /* 把任務添加到等待刪除的任務列表中,並在空閑任務中刪除 */
            vListInsertEnd( &xTasksWaitingTermination, &( pxTCB->xStateListItem ) );
            /* 記錄有多少個任務需要釋放內存 */
            ++uxDeletedTasksWaitingCleanUp;
            /* 任務刪除鈎子函數---需要用戶自己實現*/
            portPRE_TASK_DELETE_HOOK( pxTCB, &xYieldPending );
        }
        else{
            /* 要刪除的是別的任務 */
            --uxCurrentNumberOfTasks;
            prvDeleteTCB( pxTCB );
            /* 重新計算還要多長時間執行下一個任務 */
            prvResetNextTaskUnblockTime();
        }
        traceTASK_DELETE( pxTCB );
    }
    /* 退出臨界段 */
    taskEXIT_CRITICAL();

    /* 如果任務調度器開啟 */
    if( xSchedulerRunning != pdFALSE ){
        /* 如果是刪除任務本身,馬上進行任務調度)*/
        if( pxTCB == pxCurrentTCB ){
            configASSERT( uxSchedulerSuspended == 0 );
            portYIELD_WITHIN_API();
        }
        else{
            mtCOVERAGE_TEST_MARKER();
        }
    }
}

  具體的結構框圖如下所示:

 

 

(二)任務掛起函數詳解

  vTaskSuspend()函數用於掛起指定的任務,被掛起的任務失去cpu的使用權,不管是什么優先級。可以將任何狀態的任務掛起。要用此函數,INCLUDE_vTaskDelete必須定義為1。

  直接上代碼!

void vTaskSuspend(TaskHandle_t xTaskToSuspend){
    TCB_t *pxTCB;
    taskENTER_CRITICAL();
    {
        /* 獲取任務控制塊,若為NULL則掛起自身 */
        pxTCB = prvGetTCBFromHandle(xTaskToSuspend);
        /* 將任務從就緒列表、阻塞列表等中移除 */
        if(uxListRemove(&(pxTCB->xStateListItem)) == (UBaseType_t)0){
            taskRESET_READY_PRIORITY(pxTCB->uxPriority);
        }
        else{
            mtCOVERAGE_TEST_MARKER();
        }
        /* 查看任務是否在等待某個事件,如是則將其從事件列表中移除 */
        if(listLIST_ITEM_CONTAINER(&(pxTCB->xEventListItem))!=NULL){
            (void) uxListRemove(&(pxTCB->xEventListItem));
        }
        else{
            mtCOVERAGE_TEST_MARKER();
        }
        /* 將任務添加到掛起任務列表表尾 */
        vListInsertEnd(&xSuspendedTaskList, &(pxTCB->xStateListItem));
    }
    taskEXIT_CRITICAL();
    
    if(xSchedulerRunning != pdFALSE){    //如果任務調度器開啟
        /* 重新計算還要多長時間執行下一個任務 */
        taskENTER_CRITICAL();
        {
            prvResetNextTaskUnblockTime();
        }
        taskEXIT_CRITICAL();
    }
    else{
        mtCOVERAGE_TEST_MARKER();
    }

    if(pxTCB == pxCurrentTCB){
        if(xSchedulerRunning != pdFALSE){
            /* 若剛掛起的是正在運行的任務,且任務調度器運行正常,則強制進行一次任務切換 */
            configASSERT( uxSchedulerSuspended == 0 );
            portYIELD_WITHIN_API();
        }
        else{
            /* 若任務調度器沒有開啟,則讀取當前任務掛起列表的長度,判斷所有任務是否都被掛起*/
            if(listCURRENT_LIST_LENGTH(&xSuspendedTaskList) == uxCurrentNumberOfTasks){
                /* 若所有任務都被掛起,把當前的任務控制塊賦值為NULL    */
                pxCurrentTCB = NULL;
            }
            else{
                /* 若還有沒被掛起的任務,則獲取下一個要運行的任務 */
                vTaskSwitchContext();
            }
        }
    }
    else{
        mtCOVERAGE_TEST_MARKER();
    }
}

  可見任務掛起和任務刪除函數有許多共同之處。

結構圖如下,仔細分析哦

(三)任務恢復函數詳解

  任務恢復就是讓掛起的任務重新進入就緒列表,恢復的任務會保留掛起前的狀態信息,在恢復的時候根據掛起時的狀態繼續進行。如果被恢復的任務是 在所有就緒列表中的優先級最高,那么系統將進行任務上下文切換。

  直接上代碼!

void vTaskResume(TaskHandle_t xTaskToResume){
    /* 獲取要恢復的任務控制塊 */
    TCB_t * const pxTCB = (TCB_t *) xTaskToResume;
    configASSERT( xTaskToResume );

    /* 任務控制塊不能為NULL和當前任務    */
    if(( pxTCB != NULL ) && ( pxTCB != pxCurrentTCB )){
        taskENTER_CRITICAL();
        {
            /* 判斷要恢復的任務是否已經被掛起 */
            if(prvTaskIsTaskSuspended(pxTCB) != pdFALSE){
                /* 從掛起列表中移除 */
                (void) uxListRemove(&( pxTCB->xStateListItem));
                /* 添加到就緒列表中 */
                prvAddTaskToReadyList( pxTCB );
                /* 要恢復的任務優先級高於當前正在運行的任務優先級 */
                if(pxTCB->uxPriority >= pxCurrentTCB->uxPriority){
                    /* 完成一次任務切換 */
                    taskYIELD_IF_USING_PREEMPTION();
                }
                else{
                    mtCOVERAGE_TEST_MARKER();
                }
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        taskEXIT_CRITICAL();
    }
    else{
        mtCOVERAGE_TEST_MARKER();
    }
}

 

  首先要保證要恢復的任務不能是空並且不能是當前正在運行的任務,不然不需要恢復了,然后看下面的結構圖,比對着代碼就行了。

好!本章就先介紹到這里,下章介紹開啟任務調度!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM