在 FreeRTOS 中,任务删除(Task Deletion) 是一种释放系统资源、终止任务执行的机制。FreeRTOS 提供了一个核心 API 函数:
void vTaskDelete(TaskHandle_t xTaskToDelete);
这里参照:RTOS官方文档:https://www.freertos.org/zh-cn-cmn-s/Documentation/02-Kernel/04-API-references/01-Task-creation/03-vTaskDelete
vTaskDelete()
函数详解
将指定任务从 FreeRTOS 的调度系统中移除,即从所有状态列表(就绪、阻塞、挂起、事件)中删除。
void vTaskDelete(TaskHandle_t xTaskToDelete);
要删除的任务句柄。如果为 NULL,表示删除当前任务。
此函数 无返回值。删除操作成功后,任务不会再被调度执行。
任务删除的用途:① 任务执行一次性工作后退出,作用于初始化类任务、启动任务等;② 动态创建的任务完成任务后自删,可以避免浪费 RAM;③ 某个任务不再需要运行,由其他任务控制删除。例如:
void vTaskFunction(void *pvParameters)
{
// 任务执行一段逻辑
DoSomething();
// 删除自身
vTaskDelete(NULL); // ✅ 删除当前任务
}
删除其他任务:
TaskHandle_t xOtherTaskHandle;
void vOtherTask(void *pvParameters)
{
for (;;)
{
// ...
}
}
void vControllerTask(void *pvParameters)
{
// 创建其他任务
xTaskCreate(vOtherTask, "Other", 128, NULL, 2, &xOtherTaskHandle);
// 延时一段时间
vTaskDelay(1000);
// 删除其他任务
vTaskDelete(xOtherTaskHandle); // ✅删除指定任务-- 要删除的任务句柄。如果为 NULL,则删除当前任务本身
}
⚙️ 使用条件:
你必须在 FreeRTOSConfig.h
中启用此功能:
#define INCLUDE_vTaskDelete 1 // ✅ 必须为 1 才能使用此 API
工作原理:
删除任务只是将其从调度器中移除
真正释放资源的工作由“空闲任务”完成
被删除任务的 堆栈和 TCB(任务控制块) 会在空闲任务运行时被释放(动态任务)
在使用过程中需要注意的一些细节:
1. 空闲任务必须能运行:空闲任务负责清理删除任务资源,所以不能让空闲任务“饿死”(如优先级设置不当)。
2. ⚠️ 任务自己申请的内存不会被自动释放:
比如 pvPortMalloc() 创建的数据结构;
并且必须在任务删除前手动释放。其堆栈和 TCB 是用户提供的,FreeRTOS 不会自动释放这些内存。
3. 不能在中断中调用 vTaskDelete() ❌ :因为它不是 ISR 安全函数
4. 静态任务也能删除:
即使是 xTaskCreateStatic() 创建的任务也可以用 vTaskDelete() 删除,但堆栈和 TCB 不会自动释放(因为是用户提供)
vTaskDelete()
会从调度器中移除任务,适用于任务自删或控制其他任务的生命周期。空闲任务会清理动态分配的资源,因此必须确保空闲任务能被调度执行。自己分配的内存需手动释放。
代码操作:两个线程,前五秒点亮绿灯,之后删除绿灯的线程,仅留下蓝灯的闪烁
/**
******************************************************************************
* @file Project/STM32F10x_StdPeriph_Template/main.c
* @author MCD Application Team
* @version V3.5.0
* @date 08-April-2011
* @brief Main program body
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include <stdio.h>
#include "FreeRTOS.h"
#include "task.h"
#include "usart.h"
#include "gpio.h"
//------------------------- start_task --------------------------------------------//
void start_task(void *pvParameters); //任务函数入口
TaskHandle_t StartTask_Handler; //任务句柄 _任务身份证_每个任务都有独立的任务
#define START_STK_SIZE 64 //任务堆栈大小
#define START_TASK_PRO 1 //任务优先级
//-----------------------------------------------------------------------
void led_blue_task(void *pvParameters);
TaskHandle_t LED_BLUE_TASK_Handler;
int main(void)
{
NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 ); //RTOS需要将中断优先级分组分配到第四组
usart_init(115200);
MX_GPIO_Init();
printf("Create Task! \r\n");
//------------------------- start_task --------------------------------------------//
//初始化函数
xTaskCreate((TaskFunction_t) start_task, //任务函数入口
(const char * ) "start_task", //任务函数名称
(uint16_t ) START_STK_SIZE, //任务堆栈大小
(void * ) NULL, //任务参数入口
(UBaseType_t ) START_TASK_PRO, //任务优先级
(TaskHandle_t *) StartTask_Handler ); //任务句柄
vTaskStartScheduler(); //开启任务调度器
while(1) // 不会执行到这里
{}
}
void start_task(void *pvParameters) //任务函数入口
{
printf("start Task Run! \r\n");
while(1) //锁死当前线程,但并不影响其他线程的运行
{
for(int i = 0;i<5;i++)
{
GPIO_WriteBit(GPIOC, GPIO_Pin_7, Bit_RESET); //绿灯开启
vTaskDelay(500);
GPIO_WriteBit(GPIOC, GPIO_Pin_7, Bit_SET); //绿灯关闭
vTaskDelay(500);
printf("start_task Run Count; %d \r\n", i);
}
vTaskDelay(10);
taskENTER_CRITICAL(); //进入临界区,因为创建的任务不能被打断,所以开启临界区之后,中断会被屏蔽
//------------------------- led_B_task --------------------------------------------//
//初始化函数
xTaskCreate((TaskFunction_t) led_blue_task, //任务函数入口
(const char * ) "led_blue_task", //任务函数名称
(uint16_t ) 32, //任务堆栈大小
(void * ) NULL, //任务参数入口
(UBaseType_t ) 2, //任务优先级_值越大优先级越高
(TaskHandle_t *) LED_BLUE_TASK_Handler ); //蓝灯任务句柄
vTaskDelete(StartTask_Handler); //删除start_task 任务句柄
taskEXIT_CRITICAL(); //退出临界区
}
}
void led_blue_task(void *pvParameters)
{
printf("led_blue_task Run! \r\n");
while(1)
{
GPIO_WriteBit(GPIOC, GPIO_Pin_6, Bit_RESET); //蓝灯开启
vTaskDelay(200);
GPIO_WriteBit(GPIOC, GPIO_Pin_6, Bit_SET); //蓝灯关闭
vTaskDelay(200);
vTaskDelay(10);
}
}
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
任务删除后系统行为:任务被标记为“删除”
,然后在下一次任务切换时,FreeRTOS 会:① 删除任务的 TCB(动态任务);② 释放堆中为其分配的内存。因为它不会立即释放 CPU,所以任务必须结束或让出控制权。
在 FreeRTOS 中,使用 vTaskDelete()
可以安全地终止任务执行并释放资源,支持任务自删和他删,适用于一次性任务、动态创建任务的生命周期管理。
官方的介绍中这里有一段话:空闲任务会清理动态分配的资源,因此必须确保空闲任务能被调度执行。自己分配的内存需手动释放。 此处,我使用图示详细解释一下这里提到的:FreeRTOS 的任务删除后堆释放机制。
FreeRTOS 动态任务的堆内存管理流程图
为了更好的理解 FreeRTOS 的任务删除后堆释放机制,下面我通过 内存管理堆释放的示意图来可视化说明 任务创建与删除过程中堆内存的分配与释放过程。
- 使用
xTaskCreate()
创建任务时,FreeRTOS 会从堆中分配:- 任务控制块(TCB)
- 任务堆栈区
1️⃣ 任务创建后堆内存分布:
接下来,🔄 我们调用 vTaskDelete()
删除任务
- 删除任务时(
vTaskDelete()
):- 任务被标记为“已删除”
- 空闲任务会在空闲时清理并释放 TCB + 堆栈
2️⃣ 任务被标记删除,等待空闲任务清理:
3. 🧹 空闲任务运行,释放资源
3️⃣ 空闲任务释放内存 → 堆恢复可用:
说明: TCB 和堆栈都是由 FreeRTOS 堆(如 heap_4.c
)动态分配的,因此只能由空闲任务回收。
阶段 内存状态
创建任务时 从 FreeRTOS 堆中分配 TCB + 堆栈
调用 vTaskDelete() 任务被标记删除,资源未立即释放
空闲任务运行 释放对应的 TCB 和堆栈内存
完全释放后 堆中空间可再次被其他任务或对象使用
因此,通过图示我们可以知道:
- 空闲任务必须能被调度执行,否则资源不会释放,可能导致堆空间被耗尽。
- 自定义分配的内存(如任务中
pvPortMalloc()
分配的数据)不会自动释放,需要你在任务退出前手动释放。 - 静态任务(
xTaskCreateStatic()
)删除后不会释放堆,因为它 使用的是 用户提供的静态内存。
所以,FreeRTOS 中动态任务删除后,任务控制块(TCB)和堆栈由空闲任务释放,空闲任务能运行于是内存才可以回收成功。
以上,便是 FreeRTOS 任务的删除。
以上,欢迎有从事同行业的电子信息工程、互联网通信、嵌入式开发的朋友共同探讨与提问,我可以提供实战演示或模板库。希望内容能够对你产生帮助!