1. 任务创建与删除

任务创建与删除 学习卡片

任务说明

本案例基于RTOS(以FreeRTOS为例)实现两个任务的创建与删除,验证任务在就绪、运行、阻塞状态之间的转换。任务1周期性翻转LED并打印运行次数,任务2在运行5次后调用删除函数结束自身,同时由任务1删除任务2的句柄以演示外部删除。通过串口日志与LED翻转观察任务调度与状态变化。

硬件与依赖

  • 开发板:STM32F407(含LED:PA6,串口1:PA9/PA10)
  • 依赖:FreeRTOS V10.4.6(已移植至STM32),标准外设库或HAL库均可
  • 串口配置:115200-8-N-1

代码实现

// main.c 核心代码(仅展示RTOS相关部分)
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"

TaskHandle_t xTask1Handle = NULL;
TaskHandle_t xTask2Handle = NULL;

// 任务1:翻转LED,打印计数,并在任务2运行5次后删除任务2
void vTask1(void *pvParameters) {
    uint32_t ulCount = 0;
    for (;;) {
        HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_6);   // 翻转LED
        ulCount++;
        printf("Task1 running, count=%lu\r\n", ulCount);

        // 当任务2已运行5次后,由任务1删除任务2
        if (ulCount == 5) {
            if (xTask2Handle != NULL) {
                vTaskDelete(xTask2Handle);        // 外部删除任务2
                xTask2Handle = NULL;
                printf("Task1 deleted Task2\r\n");
            }
        }
        vTaskDelay(pdMS_TO_TICKS(500));           // 阻塞500ms
    }
}

// 任务2:打印运行次数,运行5次后自我删除
void vTask2(void *pvParameters) {
    uint32_t ulCount = 0;
    for (;;) {
        ulCount++;
        printf("Task2 running, count=%lu\r\n", ulCount);

        if (ulCount == 5) {
            printf("Task2 deleting itself\r\n");
            vTaskDelete(NULL);                    // 自我删除
        }
        vTaskDelay(pdMS_TO_TICKS(300));           // 阻塞300ms
    }
}

int main(void) {
    // 硬件初始化(时钟、GPIO、串口)省略,已配置完成
    xTaskCreate(vTask1, "Task1", 128, NULL, 2, &xTask1Handle);
    xTaskCreate(vTask2, "Task2", 128, NULL, 1, &xTask2Handle);
    vTaskStartScheduler();                        // 启动调度器
    // 正常情况下不会执行到这里
    for (;;);
}

任务状态转换说明

任务创建后进入就绪态,由调度器按优先级调度进入运行态。任务调用vTaskDelay()后进入阻塞态,延时结束后回到就绪态。任务2在运行5次后调用vTaskDelete(NULL)自我删除,进入删除态;任务1在计数达到5时调用vTaskDelete(xTask2Handle)删除任务2(此时任务2已自我删除,该调用实际不产生额外效果,但演示了外部删除接口的用法)。删除后的任务不再参与调度,其资源由空闲任务回收。

SVG:任务状态转换与删除时序

就绪态 运行态 阻塞态 删除态 调度 vTaskDelay 延时结束 vTaskDelete(NULL) vTaskDelete(handle) t=0 t≈2.5s(Task2第5次运行) t→∞

编译与运行

  1. 将上述代码加入STM32工程,确保FreeRTOSConfig.h中configUSE_PREEMPTION为1,configUSE_IDLE_HOOK为0。
  2. 编译并烧录至开发板。
  3. 打开串口终端(115200-8-N-1),观察输出。

验证方法与判定标准

验证步骤:

  1. 上电后观察LED(PA6)以约1Hz频率翻转(每500ms翻转一次,即亮灭周期1s)。
  2. 串口终端应交替输出Task1与Task2的运行日志,Task2输出频率高于Task1(Task2延时300ms,Task1延时500ms)。
  3. 当Task2输出第5条日志后,应看到“Task2 deleting itself”与“Task1 deleted Task2”两条删除日志。
  4. 删除后,串口不再输出Task2日志,仅Task1继续运行,LED继续翻转。

判定标准:

  • 若串口按上述顺序输出日志且LED持续翻转,则任务创建、调度、阻塞与删除功能验证通过。
  • 若Task2在输出5条日志后停止,而Task1不受影响,则任务状态转换(就绪→运行→阻塞→删除)符合预期。
  • 若Task2删除后系统无崩溃、无卡死,则说明删除操作正确释放了任务资源。

预期输出示例(与代码逻辑严格一致):

Task1 running, count=1
Task2 running, count=1
Task2 running, count=2
Task1 running, count=2
Task2 running, count=3
Task2 running, count=4
Task1 running, count=3
Task2 running, count=5
Task2 deleting itself
Task1 deleted Task2
Task1 running, count=4
Task1 running, count=5
...

注:实际输出顺序受调度时序影响,但Task2第5次运行后必然出现两条删除日志,且此后不再有Task2日志。