当前位置: 首页 > java >正文

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

在 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 任务的删除。

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

http://www.xdnf.cn/news/16236.html

相关文章:

  • 《 java 随想录》| 数组
  • Java学习日记_廖万忠
  • 支持OCR和AI解释的Web PDF阅读器:解决大文档阅读难题
  • uni-appDay02
  • #来昇腾学AI 【十天成长计划】大模型LLM Prompt初级班
  • Java学习----工厂方法模式
  • 深入理解 eMMC RPMB 与 OP-TEE 在 Linux 系统中的应用开发
  • day62-可观测性建设-全链路监控zabbix+grafana
  • 爬虫算法原理解析
  • Windows环境下 Go项目迁移至Ubuntu(WSL) 以部署filebeat为例
  • MinIO 版本管理实践指南(附完整 Go 示例)
  • MySQL深度理解-MySQL索引优化
  • 二分查找----5.寻找旋转排序数组中的最小值
  • Android Activity与Fragment生命周期变化
  • 谈谈ArrayList与Vector的理解?
  • NOTEPAD!NPCommand函数分析之comdlg32!GetSaveFileNameW--windows记事本源代码分析
  • TechGPT3部署
  • 【STM32】FreeRTOS 任务的创建(二)
  • 深入理解大语言模型生成参数:temperature、top\_k、top\_p 等全解析
  • EasyExcel 模板导出数据 + 自定义策略(合并单元格)
  • vue 项目中 components 和 views 包下的组件功能区别对比,示例演示
  • AudioLLM 开源项目了解学习
  • 网络编程——聊天程序实现
  • 基于arduino uno r3主控的环境监测系统设计-2
  • 后端分页接口实现
  • SpringBoot框架简介
  • PHP 与 Vue.js 结合的前后端分离架构
  • Qwen3-Coder实现中国象棋游戏的尝试
  • DRF - 博客列表API
  • 【C++】类和对象(中)