【STM32】FreeRTOS 任务的删除(三)

在 FreeRTOS 中,任务删除(Task Deletion) 是一种释放系统资源、终止任务执行的机制。FreeRTOS 提供了一个核心 API 函数:

c 复制代码
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;③ 某个任务不再需要运行,由其他任务控制删除。例如:

c 复制代码
void vTaskFunction(void *pvParameters)
{
    // 任务执行一段逻辑
    DoSomething();

    // 删除自身
    vTaskDelete(NULL);  // ✅ 删除当前任务
}

删除其他任务:

c 复制代码
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 中启用此功能:

c 复制代码
#define INCLUDE_vTaskDelete 1  // ✅ 必须为 1 才能使用此 API
复制代码
工作原理:
	删除任务只是将其从调度器中移除
	真正释放资源的工作由"空闲任务"完成
	被删除任务的 堆栈和 TCB(任务控制块) 会在空闲任务运行时被释放(动态任务)

在使用过程中需要注意的一些细节:
	1. 空闲任务必须能运行:空闲任务负责清理删除任务资源,所以不能让空闲任务"饿死"(如优先级设置不当)。
	2. ⚠️ 任务自己申请的内存不会被自动释放:
		 	比如 pvPortMalloc() 创建的数据结构;
		 	并且必须在任务删除前手动释放。其堆栈和 TCB 是用户提供的,FreeRTOS 不会自动释放这些内存。
	3. 不能在中断中调用 vTaskDelete() ❌ :因为它不是 ISR 安全函数
	4. 静态任务也能删除:
			即使是 xTaskCreateStatic() 创建的任务也可以用 vTaskDelete() 删除,但堆栈和 TCB 不会自动释放(因为是用户提供)

vTaskDelete() 会从调度器中移除任务,适用于任务自删或控制其他任务的生命周期。空闲任务会清理动态分配的资源,因此必须确保空闲任务能被调度执行。自己分配的内存需手动释放。

代码操作:两个线程,前五秒点亮绿灯,之后删除绿灯的线程,仅留下蓝灯的闪烁

c 复制代码
/**
  ******************************************************************************
  * @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>&copy; 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 的任务删除后堆释放机制 ,下面我通过 内存管理堆释放的示意图来可视化说明 任务创建与删除过程中堆内存的分配与释放过程。

  1. 使用 xTaskCreate() 创建任务时,FreeRTOS 会从堆中分配:
    • 任务控制块(TCB)
    • 任务堆栈区

1️⃣ 任务创建后堆内存分布:

接下来,🔄 我们调用 vTaskDelete() 删除任务

  1. 删除任务时(vTaskDelete()):
    • 任务被标记为"已删除"
    • 空闲任务会在空闲时清理并释放 TCB + 堆栈

2️⃣ 任务被标记删除,等待空闲任务清理:

  1. 🧹 空闲任务运行,释放资源

3️⃣ 空闲任务释放内存 → 堆恢复可用:

说明: TCB 和堆栈都是由 FreeRTOS 堆(如 heap_4.c)动态分配的,因此只能由空闲任务回收。

复制代码
阶段								内存状态
创建任务时						从 FreeRTOS 堆中分配 TCB + 堆栈
调用 vTaskDelete()				任务被标记删除,资源未立即释放
空闲任务运行						释放对应的 TCB 和堆栈内存
完全释放后						堆中空间可再次被其他任务或对象使用

因此,通过图示我们可以知道:

  • 空闲任务必须能被调度执行,否则资源不会释放,可能导致堆空间被耗尽。
  • 自定义分配的内存(如任务中 pvPortMalloc() 分配的数据)不会自动释放,需要你在任务退出前手动释放。
  • 静态任务(xTaskCreateStatic())删除后不会释放堆,因为它 使用的是 用户提供的静态内存。

所以,FreeRTOS 中动态任务删除后,任务控制块(TCB)和堆栈由空闲任务释放,空闲任务能运行于是内存才可以回收成功。

以上,便是 FreeRTOS 任务的删除。

以上,欢迎有从事同行业的电子信息工程、互联网通信、嵌入式开发的朋友共同探讨与提问,我可以提供实战演示或模板库。希望内容能够对你产生帮助!

相关推荐
冬天vs不冷1 分钟前
Java基础(十一):关键字final详解
java·开发语言
轻松Ai享生活2 分钟前
一文搞懂应用程序 core dump 和内核 core dump
linux
上官浩仁4 分钟前
springboot maven 多环境配置入门与实战
java·spring boot·maven
云飞云共享云桌面5 分钟前
1台电脑10个画图设计用怎么实现
linux·运维·服务器·网络·数据库·自动化·电脑
元直数字电路验证6 分钟前
新建Jakarta EE项目,Maven Archetype 选项无法加载出内容该怎么办?
java·maven
小MarkK8 分钟前
[Ubuntu][mount]ubuntu电脑挂载新硬盘
linux·ubuntu·电脑·mount·硬盘挂载
我叫汪枫15 分钟前
Spring Boot图片验证码功能实现详解 - 从零开始到完美运行
java·前端·javascript·css·算法·html
艾莉丝努力练剑19 分钟前
【Linux】初始Linux:从计算机历史发展、操作系统历史脉络的角度详谈Linux相关的话题,附Linux安装和用户创建(环境准备)详解
linux·运维·服务器·经验分享
小王不爱笑13220 分钟前
Java基础知识(十四)
java·windows·python
l1t27 分钟前
how to build tbox xml into the demo
xml·linux·c语言·parser·tbox