4. 任务删除与自我删除
任务目标
本案例演示FreeRTOS中任务删除的两种典型用法:任务自我删除(任务运行完毕后调用vTaskDelete(NULL)回收自身)与任务删除其他任务(通过任务句柄删除指定任务)。最终通过LED闪烁与串口日志验证删除行为是否符合预期。
核心知识点
vTaskDelete(TaskHandle_t pxTask):删除参数指定的任务;传入NULL时删除当前运行任务(自我删除)。- 被删除任务进入就绪态后,其TCB与栈空间由空闲任务负责释放,因此必须确保空闲任务不被阻塞或挂起。
- 任务删除后,其句柄不再有效,不应再次调用
vTaskDelete或vTaskSuspend等API操作该句柄。
完整代码
#include "FreeRTOS.h"
#include "task.h"
#include "led.h" // 板级LED驱动,提供 LED_Init/LED_On/LED_Off
#include "debug.h" // 板级串口驱动,提供 DEBUG_Init/DEBUG_Printf
/* 任务句柄 */
static TaskHandle_t xTaskDeleteeHandle = NULL; // 被删除任务句柄
static TaskHandle_t xTaskDeleterHandle = NULL; // 执行删除操作的任务句柄
/* 任务1:运行5次后自我删除 */
static void vTaskSelfDelete(void *pvParameters)
{
uint8_t ucCount = 0;
const TickType_t xDelay = pdMS_TO_TICKS(200);
for (;;)
{
ucCount++;
LED_On();
vTaskDelay(xDelay);
LED_Off();
vTaskDelay(xDelay);
DEBUG_Printf("Self-delete task running, count = %d\r\n", ucCount);
if (ucCount >= 5)
{
DEBUG_Printf("Self-delete task will delete itself now.\r\n");
vTaskDelete(NULL); // 自我删除
}
}
}
/* 任务2:延时后删除任务1 */
static void vTaskDeleteOther(void *pvParameters)
{
const TickType_t xDelay500ms = pdMS_TO_TICKS(500);
const TickType_t xDelay2s = pdMS_TO_TICKS(2000);
vTaskDelay(xDelay2s); // 等待任务1先运行一段时间
if (xTaskDeleteeHandle != NULL)
{
DEBUG_Printf("Deleter task is deleting the self-delete task.\r\n");
vTaskDelete(xTaskDeleteeHandle); // 删除任务1
xTaskDeleteeHandle = NULL; // 句柄置空,防止悬垂指针
}
/* 再延时后自我删除,结束本任务 */
vTaskDelay(xDelay500ms);
DEBUG_Printf("Deleter task finishes its job, delete itself.\r\n");
vTaskDelete(NULL);
}
int main(void)
{
LED_Init();
DEBUG_Init();
/* 创建任务1:自我删除 */
xTaskCreate(vTaskSelfDelete, "SelfDel", 128, NULL, 2, &xTaskDeleteeHandle);
/* 创建任务2:删除其他任务 */
xTaskCreate(vTaskDeleteOther, "Deleter", 128, NULL, 1, &xTaskDeleterHandle);
vTaskStartScheduler();
/* 正常不会运行到这里 */
for (;;);
}
运行与验证
- 编译与烧录:将代码加入FreeRTOS工程(需包含
led.c/h与debug.c/h板级驱动),编译后烧录至开发板。 - 预期行为:
- 任务1(优先级2)每200ms翻转一次LED,并打印运行次数;运行5次后打印删除信息并自我删除。
- 任务2(优先级1)启动后延时2秒,此时任务1已运行约5次(每次400ms周期),任务2随即删除任务1,打印删除信息。
- 任务2再延时500ms后自我删除。此后系统中仅剩空闲任务,LED停止翻转,串口不再输出。
- 判定通过条件:
- 串口依次输出任务1的5次计数(count=1~5)、任务1自我删除信息、任务2删除任务1的信息、任务2自我删除信息。
- LED在任务1运行期间持续闪烁,任务1被删除后LED停止变化。
- 系统不崩溃、不死机,空闲任务正常运行。
关键说明
- 任务1的
xTaskDeleteeHandle在创建时被赋值,任务2通过该句柄删除任务1。删除后立即将句柄置NULL,避免后续误用。 - 自我删除使用
vTaskDelete(NULL),当前任务停止运行并进入待回收状态,内存由空闲任务释放。 - 若任务2先于任务1完成删除(例如调整延时),需保证任务1尚未自我删除,否则句柄已失效。本案例中任务1运行5次约需2秒(5×400ms),任务2延时2秒后删除,时序上任务1恰好刚完成第5次自我删除,此时任务2再调用
vTaskDelete操作已删除任务的句柄属于未定义行为。因此实际测试时建议将任务2延时调整为1.5秒(xDelay2s = pdMS_TO_TICKS(1500)),确保任务1仍在运行状态时被任务2删除,从而清晰展示“删除其他任务”的效果。