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(); } }
首先要保证要恢复的任务不能是空并且不能是当前正在运行的任务,不然不需要恢复了,然后看下面的结构图,比对着代码就行了。
好!本章就先介绍到这里,下章介绍开启任务调度!