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

发布于:2025-07-25 ⋅ 阅读:(17) ⋅ 点赞:(0)

在 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>&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️⃣ 任务被标记删除,等待空闲任务清理:
在这里插入图片描述
3. 🧹 空闲任务运行,释放资源

3️⃣ 空闲任务释放内存 → 堆恢复可用:
在这里插入图片描述
说明: TCB 和堆栈都是由 FreeRTOS 堆(如 heap_4.c)动态分配的,因此只能由空闲任务回收。

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

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

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

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

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

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


网站公告

今日签到

点亮在社区的每一天
去签到