以下是添加了详细中文注释的 vTaskDelete函数,逐段解释其逻辑和关键操作:
函数定义与变量声明
void vTaskDelete(TaskHandle_t xTaskToDelete)
{
TCB_t *pxTCB; // 指向任务控制块(TCB)的指针
-
功能:删除指定的FreeRTOS任务。
-
参数:
xTaskToDelete:要删除的任务句柄(若为NULL则删除当前任务)。
进入临界区
taskENTER_CRITICAL(); // 进入临界区,防止任务调度干扰
{
- 作用:保护任务删除操作的原子性。
获取任务TCB
/* 若参数为NULL,则删除当前正在运行的任务 */
pxTCB = prvGetTCBFromHandle(xTaskToDelete);
-
关键点:
-
prvGetTCBFromHandle:将任务句柄转换为TCB结构体指针。 -
若传入
NULL,内部会自动获取当前任务的TCB。
-
从就绪/阻塞列表中移除任务
cpp
/* 将任务从就绪/阻塞列表中移除 */
if (uxListRemove(&(pxTCB->xStateListItem)) == (UBaseType_t)0)
{
taskRESET_READY_PRIORITY(pxTCB->uxPriority); // 若该优先级无其他任务,清除就绪位
}
else
{
mtCOVERAGE_TEST_MARKER(); // 覆盖率测试标记(无实际代码)
}
-
逻辑:
-
uxListRemove:从列表移除任务,返回剩余任务数。 -
若返回0,表示该优先级无其他就绪任务,需重置优先级位图。
-
检查事件等待列表
cpp
/* 检查任务是否在等待事件(如信号量、队列) */
if (listLIST_ITEM_CONTAINER(&(pxTCB->xEventListItem)) != NULL)
{
(void)uxListRemove(&(pxTCB->xEventListItem)); // 从事件列表中移除
}
else
{
mtCOVERAGE_TEST_MARKER();
}
- 作用:确保任务不会因删除导致事件列表出现悬空指针。
更新任务编号
/* 递增任务编号,便于调试工具检测任务列表变化 */
uxTaskNumber++;
- 用途:内核感知型调试器可通过此值判断任务列表是否需要刷新。
处理当前任务自删除
cpp
if (pxTCB == pxCurrentTCB) // 如果是当前任务删除自身
{
/* 将任务TCB插入终止列表,由空闲任务负责内存回收 */
vListInsertEnd(&xTasksWaitingTermination, &(pxTCB->xStateListItem));
/* 通知空闲任务有任务待清理 */
++uxDeletedTasksWaitingCleanUp;
/* 调用跟踪钩子函数(用于调试) */
traceTASK_DELETE(pxTCB);
/* 平台特定的删除前钩子(如Windows模拟器清理) */
portPRE_TASK_DELETE_HOOK(pxTCB, &xYieldPending);
}
-
关键流程:
-
自删除任务无法立即释放资源(需切换上下文)。
-
将TCB放入终止列表,由空闲任务异步回收内存。
-
钩子函数用于平台特定清理(如模拟器环境)。
-
处理其他任务删除
cpp
else // 删除其他任务
{
--uxCurrentNumberOfTasks; // 更新全局任务计数器
traceTASK_DELETE(pxTCB); // 调试跟踪
prvDeleteTCB(pxTCB); // 直接释放TCB和栈内存
/* 重置下一个任务解除阻塞时间(避免引用已删除任务) */
prvResetNextTaskUnblockTime();
}
-
区别:
-
非自删除任务可直接同步释放资源。
-
需检查并更新调度器的时间基准。
-
退出临界区
}
taskEXIT_CRITICAL(); // 退出临界区
- 作用:恢复中断和任务调度。
触发任务调度
cpp
/* 若删除的是当前任务且调度器已启动,强制触发上下文切换 */
if (xSchedulerRunning != pdFALSE)
{
if (pxTCB == pxCurrentTCB) // 自删除场景
{
configASSERT(uxSchedulerSuspended == 0); // 确保调度器未挂起
portYIELD_WITHIN_API(); // 主动让出CPU
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
-
关键点:
-
自删除任务必须立即切换上下文,否则会继续执行非法内存。
-
portYIELD_WITHIN_API:触发调度器选择下一个就绪任务。
-
总结流程图
开始
│
├─ 进入临界区
│ ├─ 获取TCB
│ ├─ 从就绪/阻塞列表移除
│ ├─ 从事件列表移除(若存在)
│ │
│ ├─ 如果是自删除任务:
│ │ ├─ 加入终止列表
│ │ ├─ 通知空闲任务清理
│ │ └─ 调用平台钩子
│ │
│ └─ 如果是其他任务:
│ ├─ 释放TCB内存
│ └─ 重置解除阻塞时间
│
└─ 退出临界区
│
└─ 若自删除且调度器运行:
└─ 强制上下文切换
结束
注意事项
-
内存安全:
- 自删除任务的栈和TCB由空闲任务回收,需确保空闲任务有执行机会。
-
资源泄漏:
- 任务删除前应释放其占用的所有资源(如动态内存、外设句柄)。
-
实时性:
- 在中断中调用时,需使用
xTaskDeleteFromISR并处理上下文切换请求。
- 在中断中调用时,需使用