FreeRTOS任务创建到任务运行完整运行顺序及空闲任务清理资源详细介绍
·
int main(void)
{
BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */
BSP_Init();
printf("这是一个[野火]-STM32全系列开发板-FreeRTOS-动态创建任务!\r\n");
xReturn = xTaskCreate((TaskFunction_t )AppTaskCreate, /* 任务入口函数 */
(const char* )"AppTaskCreate",/* 任务名字 */
(uint16_t )512, /* 任务栈大小 */
(void* )NULL,/* 任务入口函数参数 */
(UBaseType_t )1, /* 任务的优先级 */
(TaskHandle_t* )&AppTaskCreate_Handle);/* 任务控制块指针 */
if(pdPASS == xReturn)
vTaskStartScheduler(); /* 启动任务,开启调度 */
else
return -1;
while(1); /* 正常不会执行到这里 */
}
static void AppTaskCreate(void)
{
BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */
taskENTER_CRITICAL(); //进入临界区
xReturn = xTaskCreate((TaskFunction_t )LED_Task, /* 任务入口函数 */
(const char* )"LED_Task",/* 任务名字 */
(uint16_t )512, /* 任务栈大小 */
(void* )NULL, /* 任务入口函数参数 */
(UBaseType_t )2, /* 任务的优先级 */
(TaskHandle_t* )&LED_Task_Handle);/* 任务控制块指针 */
if(pdPASS == xReturn)
printf("创建LED_Task任务成功!\r\n");
xReturn = xTaskCreate((TaskFunction_t )LED2_Task, /* 任务入口函数 */
(const char* )"LED2_Task",/* 任务名字 */
(uint16_t )512, /* 任务栈大小 */
(void* )NULL, /* 任务入口函数参数 */
(UBaseType_t )2, /* 任务的优先级 */
(TaskHandle_t* )&LED2_Task_Handle);/* 任务控制块指针 */
if(pdPASS == xReturn)
printf("创建LED2_Task任务成功!\r\n");
vTaskDelete(AppTaskCreate_Handle); //删除AppTaskCreate任务
taskEXIT_CRITICAL(); //退出临界区
}
static void LED_Task(void* parameter)
{
while (1)
{
LED1_ON;
vTaskDelay(500); /* 延时500个tick */
printf("LED_Task Running,LED1_ON\r\n");
LED1_OFF;
vTaskDelay(500); /* 延时500个tick */
printf("LED_Task Running,LED1_OFF\r\n");
}
}
static void LED2_Task(void* parameter)
{
while (1)
{
LED2_ON;
vTaskDelay(1000); /* 延时500个tick */
printf("LED_Task Running,LED2_ON\r\n");
LED2_OFF;
vTaskDelay(1000); /* 延时500个tick */
printf("LED_Task Running,LED2_OFF\r\n");
}
}
一、Main 函数阶段:任务注册(未执行任务逻辑)
main 函数是程序的入口,此时 FreeRTOS 调度器未启动,CPU 完全由 main 函数掌控,执行顺序如下:
- 初始化返回值变量:定义
xReturn并赋值为pdPASS,用于接收任务创建的返回状态。 - 硬件初始化:调用
BSP_Init()完成开发板底层硬件初始化(如 GPIO、串口、时钟等),为后续任务运行提供硬件支持。 - 打印提示信息:通过
printf输出日志,此时串口已在BSP_Init()中初始化完成。 - 注册 AppTaskCreate 任务:调用
xTaskCreate函数,该函数的作用是将 AppTaskCreate 任务的信息注册到 FreeRTOS 内核的任务列表中,并非立即执行任务逻辑:- 内核会为该任务分配栈空间、初始化任务控制块(TCB),并将任务加入 “就绪队列”(此时任务处于 “就绪态”,等待调度)。
- 此时 CPU 仍在 main 函数中,AppTaskCreate 的任务逻辑(函数体内部代码)完全未执行。
- 判断任务创建结果:若
xReturn为pdPASS(说明 AppTaskCreate 任务注册成功),则调用vTaskStartScheduler();否则返回 - 1,程序异常退出。 - 启动任务调度器(关键步骤):
vTaskStartScheduler()是 FreeRTOS 的核心函数,执行以下操作:- 初始化调度器相关内核资源(如就绪列表、定时器等)。
- 根据任务优先级,从就绪队列中选出最高优先级的就绪任务(此时仅有 AppTaskCreate 任务,优先级为 1)。
- 执行上下文切换:保存 main 函数的运行上下文(寄存器、栈指针等),恢复 AppTaskCreate 任务的上下文,将 CPU 控制权交给该任务。
- 至此,AppTaskCreate 任务才开始真正执行(而非创建后直接执行)。
- main 函数的死循环:
vTaskStartScheduler()启动调度器后,若调度器正常运行,永远不会返回(后续 CPU 被任务调度器管理),因此while(1)不会被执行。
二、AppTaskCreate 任务阶段:创建业务任务并自我删除
当调度器完成上下文切换后,CPU 开始执行 AppTaskCreate 函数的逻辑,执行顺序如下:
- 初始化 LED 任务创建返回值:定义
xReturn并赋值为pdPASS,用于接收 LED_Task 和 LED2_Task 的创建状态。 - 进入临界区(保证任务创建原子性):调用
taskENTER_CRITICAL(),作用是关闭全局中断(或禁止任务调度,取决于 FreeRTOS 配置),防止在创建 LED 任务的过程中,被中断或其他任务(此时暂无其他任务)打断,确保两个 LED 任务的创建过程完整、有序执行。 - 创建 LED_Task 任务:
- 调用
xTaskCreate注册 LED_Task 任务,配置任务栈 512 字节、优先级 2、任务句柄LED_Task_Handle,无入口参数。 - 若创建成功(
xReturn == pdPASS),打印 “创建 LED_Task 任务成功!”,此时 LED_Task 进入 “就绪态”,但因处于临界区,调度器被禁止,无法执行。
- 调用
- 创建 LED2_Task 任务:
- 同理,调用
xTaskCreate注册 LED2_Task 任务,配置参数与 LED_Task 一致(栈 512 字节、优先级 2、句柄LED2_Task_Handle)。 - 若创建成功,打印 “创建 LED2_Task 任务成功!”,LED2_Task 同样进入 “就绪态”,等待调度。
- 同理,调用
- 自我删除 AppTaskCreate 任务:调用
vTaskDelete(AppTaskCreate_Handle),将自身任务标记为 “待删除态”:- 该任务不会立即终止,会继续执行后续代码(退出临界区),其资源(栈、TCB)会由 FreeRTOS 空闲任务后续清理。
- 此时 AppTaskCreate 的使命(创建业务任务)已完成,自我删除可释放系统资源,避免无效占用。
- 退出临界区(恢复任务调度):调用
taskEXIT_CRITICAL(),恢复全局中断和任务调度功能,此时调度器立即生效:- 就绪队列中存在两个高优先级任务(LED_Task、LED2_Task,优先级 2,高于 AppTaskCreate 的优先级 1),调度器会从这两个同优先级任务中选择一个,执行上下文切换,将 CPU 控制权交给它。
- 至此,AppTaskCreate 任务完成所有逻辑,后续由空闲任务清理其资源,不再参与调度。
为何 AppTaskCreate 任务被删除后,会切换到 LED_Task 和 LED2_Task?
在 AppTaskCreate 任务中,创建 LED_Task 和 LED2_Task 的过程,早已为 “切换到这两个任务” 做好了准备:
- 当调用
xTaskCreate创建 LED_Task 和 LED2_Task 时,FreeRTOS 内核已经完成了这两个任务的注册:分配栈空间、初始化 TCB、并将它们加入到「就绪队列」中,此时这两个任务处于 **“就绪态”**(具备执行条件,只等待 CPU 控制权)。 - 之所以这两个高优先级任务没有立即执行,仅仅是因为 AppTaskCreate 任务调用了
taskENTER_CRITICAL()进入了临界区 —— 临界区会禁止任务调度(阻断上下文切换),即便有更高优先级的就绪任务,调度器也无法切换 CPU 控制权,只能等待临界区退出。
三、最终阶段:LED_Task 与 LED2_Task 循环执行
调度器切换到 LED_Task/LED2_Task 后,两个任务按 FreeRTOS 调度策略运行(默认抢占式 + 时间片轮转):
- 若任务是循环逻辑(通常 LED 任务为 “延时 - 翻转 LED - 再延时” 的循环),则会持续运行,周期性执行 LED 控制操作。
- 同优先级的两个任务会交替获得 CPU 控制权,实现 “并发” 执行效果(宏观上同时运行,微观上分时切换)。
四、FreeRTOS 空闲任务(Idle Task)的基础定位
当你调用vTaskStartScheduler()启动调度器时,FreeRTOS 会自动创建一个最低优先级(优先级为 0)的空闲任务,它是系统必有的系统任务,具有两个核心作用:
- 当系统中没有其他更高优先级的就绪任务时,CPU 会执行空闲任务(避免 CPU 处于 “无任务可执行” 的空转状态)。
- 负责清理被
vTaskDelete()标记为 “待删除态” 的任务资源
五、待清理的资源:被删除任务的两大核心资源
代码中,vTaskDelete(AppTaskCreate_Handle)只是将 AppTaskCreate 任务标记为 “待删除态”,并未立即释放资源,这些待清理的资源主要有两类:
1. 任务栈(Task Stack)
- 每个任务创建时(
xTaskCreate动态创建),FreeRTOS 会从堆空间中为任务分配指定大小的栈空间(你的代码中是 512 字节)。 - 任务栈的作用:存储任务运行时的临时数据(局部变量、函数调用参数)、上下文切换时的寄存器值、返回地址等,是任务运行的 “临时内存空间”。
- 当任务被标记为待删除后,该栈空间不会立即释放,若长期不清理,会造成堆内存泄漏,后续无法为新任务分配栈空间。
2. 任务控制块(Task Control Block,TCB)
- TCB 是每个任务的 “身份信息与管理载体”,是一个结构体,包含了任务的优先级、任务状态(就绪 / 阻塞 / 挂起)、栈指针、任务句柄、任务名称等核心管理信息。
- 动态创建任务时,TCB 同样从堆空间中分配内存,它是 FreeRTOS 内核管理任务的 “核心数据结构”,被删除后若不回收,会持续占用堆内存,且占用内核任务列表的无效节点。
除此之外,若任务创建时还有其他动态分配的附属资源(如任务私有缓冲区),空闲任务不会自动清理(需用户在任务删除前手动释放),但上述栈和 TCB 是空闲任务的默认清理对象。
六、清理的时机与具体过程
1. 清理时机:仅当无更高优先级任务就绪时
空闲任务是最低优先级(0),遵循 “高优先级任务优先执行” 的调度规则,只有满足以下条件时,空闲任务才会获得 CPU 控制权,执行资源清理:
- 系统中所有高优先级任务(你的代码中是 LED_Task、LED2_Task,优先级 2)都处于 “阻塞态”(如调用
vTaskDelay()延时)或 “挂起态”,没有就绪任务可执行。 - 例如:当 LED_Task 和 LED2_Task 都在执行
vTaskDelay()进入阻塞态时,CPU 无业务任务可执行,此时调度器会切换到空闲任务,空闲任务便会执行资源清理工作。
2. 具体清理过程
- 空闲任务运行时,会遍历 FreeRTOS 内核的 “待删除任务列表”(所有被
vTaskDelete()标记的任务都会进入该列表)。 - 对于列表中的每个待删除任务,首先释放其占用的任务栈内存(将栈空间归还给堆管理器,供后续新任务创建使用)。
- 接着释放任务 TCB 的内存(将 TCB 结构体占用的堆空间回收,同时将该任务从内核的所有管理列表(就绪列表、阻塞列表等)中移除,标记为无效任务)。
- 清理完成后,将该任务从 “待删除任务列表” 中移除,至此,被删除任务的所有默认资源已完全释放,不会造成内存泄漏。
- 若待删除任务列表为空,空闲任务会进入 “空循环”(轻量级空转,尽量减少 CPU 占用),直到有高优先级任务就绪,调度器会立即切换 CPU 控制权。
七、AppTaskCreate 任务的资源清理流程
- AppTaskCreate 任务调用
vTaskDelete(AppTaskCreate_Handle)后,自身被标记为 “待删除态”,进入待删除任务列表,此时它的栈和 TCB 仍占用堆内存。 - AppTaskCreate 任务执行完
taskEXIT_CRITICAL()后,调度器切换到 LED_Task/LED2_Task(优先级 2 更高),这两个任务正常运行,空闲任务处于就绪态等待。 - 当 LED_Task 执行
vTaskDelay(500)、LED2_Task 执行vTaskDelay(1000)时,两个任务均进入阻塞态,系统中无就绪的高优先级任务。 - 调度器将 CPU 控制权交给空闲任务(优先级 0),空闲任务遍历待删除任务列表,找到 AppTaskCreate 任务。
- 空闲任务依次释放 AppTaskCreate 任务的 512 字节栈空间和 TCB 内存,将这些内存归还给堆管理器。
- 清理完成后,AppTaskCreate 任务从所有内核列表中移除,后续不再参与任何调度,其资源可被新任务(若有)复用。
总结
- 空闲任务是 FreeRTOS 自动创建的最低优先级任务,资源清理是其核心职责之一。
- 清理的核心资源是被删除任务的动态分配任务栈和TCB 结构体,避免堆内存泄漏。
- 清理时机是 “无更高优先级任务就绪时”,不会影响业务任务的正常执行。
- 你的代码中,AppTaskCreate 任务的资源会在 LED 任务阻塞期间,由空闲任务自动回收,无需手动干预。
更多推荐


所有评论(0)