FreeRTOS(2)——静态任务创建和删除
本文最后更新于20 天前,其中的信息可能已经过时,如有错误请发送邮件到big_fw@foxmail.com

FreeRTOS 创建任务有动态和静态两种方式。动态创建时,任务控制块 TCB 和任务栈由 FreeRTOS 从堆中申请;静态创建时,这两块内存由用户提前定义,再交给 FreeRTOS 使用。

静态创建的核心价值是确定性:任务创建时不再依赖堆分配,也就避免了运行期因为堆不足导致创建失败的问题。它适合对内存位置、内存占用和可靠性要求更明确的场景。

一、静态创建任务 API

使用静态创建任务,需要在 FreeRTOSConfig.h 中打开:

#define configSUPPORT_STATIC_ALLOCATION    1

静态创建任务函数:

TaskHandle_t xTaskCreateStatic(
   TaskFunction_t pxTaskCode,
   const char * const pcName,
   const uint32_t ulStackDepth,
   void * const pvParameters,
   UBaseType_t uxPriority,
   StackType_t * const puxStackBuffer,
   StaticTask_t * const pxTaskBuffer
);

参数重点如下:

参数作用
pxTaskCode任务入口函数
pcName任务名称
ulStackDepth任务栈大小,单位是字,不是字节
pvParameters传给任务入口函数的参数
uxPriority任务优先级
puxStackBuffer用户提供的任务栈数组
pxTaskBuffer用户提供的任务控制块

xTaskCreate() 不同,xTaskCreateStatic() 返回值就是任务句柄。创建成功返回任务句柄,失败返回 NULL

最小调用形式如下:

static StaticTask_t task1_tcb;
static StackType_t task1_stack[128];

task1_handle = xTaskCreateStatic(
   task1,
   "task1",
   128,
   NULL,
   2,
   task1_stack,
   &task1_tcb
);

这段代码的重点是:task1_tcbtask1_stack 都由用户提供,而不是 FreeRTOS 从堆中申请。

二、静态创建的使用流程

静态创建可以按五步理解:

  1. 打开 configSUPPORT_STATIC_ALLOCATION
  2. 为系统空闲任务提供 TCB 和任务栈。
  3. 如果启用了软件定时器,也要为定时器任务提供 TCB 和任务栈。
  4. 为用户任务定义 TCB、任务栈和入口函数。
  5. 调用 xTaskCreateStatic() 创建任务。

静态创建比动态创建多出来的复杂度,主要就在“用户自己准备内存”这一步。

三、为什么要提供空闲任务内存

FreeRTOS 调度器启动后,系统至少会创建一个空闲任务。动态分配时,这个任务的 TCB 和栈可以由内核从堆中申请;静态分配时,这些内存也必须由用户提供。

因此需要实现:

void vApplicationGetIdleTaskMemory(
   StaticTask_t **ppxIdleTaskTCBBuffer,
   StackType_t **ppxIdleTaskStackBuffer,
   configSTACK_DEPTH_TYPE *pulIdleTaskStackSize
);

如果工程启用了软件定时器:

#define configUSE_TIMERS    1

还需要实现:

void vApplicationGetTimerTaskMemory(
   StaticTask_t **ppxTimerTaskTCBBuffer,
   StackType_t **ppxTimerTaskStackBuffer,
   configSTACK_DEPTH_TYPE *pulTimerTaskStackSize
);

这两个接口的作用不是创建任务逻辑,而是告诉 FreeRTOS:空闲任务和定时器任务可以使用哪一块 TCB、哪一块栈。

四、任务删除 API

静态创建的任务,删除时仍然使用同一个函数:

void vTaskDelete(TaskHandle_t xTaskToDelete);

使用前需要打开:

#define INCLUDE_vTaskDelete    1

示例:

vTaskDelete(task1_handle);  /* 删除指定任务 */
vTaskDelete(NULL);          /* 删除当前任务 */

删除任务后,FreeRTOS 会把该任务从就绪、阻塞、挂起、事件等列表中移除,使它不再参与调度。

不过,静态任务的 TCB 和任务栈是用户提供的静态内存,FreeRTOS 不会把它们归还给堆。任务删除后,这些数组和结构体仍然存在,后续如果需要重新创建任务,可以继续复用。

五、静态创建内部做了什么

xTaskCreateStatic() 内部大致流程如下:

  1. 获取用户传入的 TCB 地址。
  2. 获取用户传入的任务栈地址。
  3. 标记该任务使用静态分配方式。
  4. 初始化任务控制块 TCB。
  5. 初始化任务栈,为上下文切换准备现场。
  6. 将任务加入对应优先级的就绪列表。
  7. 返回任务句柄。

可以看到,静态创建和动态创建后半段是一样的,都会初始化 TCB、初始化任务栈、加入就绪列表。真正的区别在前半段:动态创建由 FreeRTOS 申请内存,静态创建由用户提供内存。

六、实验设计思路

与动态创建任务的实验现象一致。

本实验使用野火指南者开发板,主控芯片为 STM32F103VET6, 平台使用 STM32CubeIDE,故不是 FreeRTOS 原生接口,而是由 CMSIS-RTOS v2 *封装的 FreeRTOS API*

实验说明:板载 LED 是一个 RGB 灯,不适合用多个独立 LED 分别表示多个任务,因此这里用不同颜色来区分任务现象:不同任务按照不同周期控制 RGB 灯显示不同颜色。

这个实验只围绕两个问题展开:

  1. 观察任务是如何被静态创建出来的。
  2. 观察指定任务被删除后,它对应的现象是否停止。

任务分工如下:

任务作用
start_task周期打印串口信息,作为系统仍在运行的心跳
task1每隔 1s 控制 RGB LED 显示蓝色
task2每隔 1.2s 控制 RGB LED 显示绿色,作为被删除的目标任务

按键触发前,start_task 会持续打印串口信息,说明调度器仍在正常运行;task1task2 也会按照各自周期运行。由于两个任务的周期分别是 1s1.2s,蓝色和绿色的切换节奏会不断错开,过一段时间后又重新接近重合。

按键触发后,中断服务函数不直接删除任务,而是只设置一个 volatile 标志位。随后在任务上下文中检测这个标志位,并删除 task2。删除成功后,绿色不再出现,RGB LED 只保留 task1 对应的蓝色变化;同时串口心跳仍然继续打印,说明删除的是指定任务,而不是整个系统停止运行。

这个实验的观察重点不是 RGB 灯本身,而是通过 RGB 灯和串口现象确认两件事:任务删除后,对应任务的行为会停止;其他未被删除的任务仍然可以继续被调度。

Github:Hui404/FreeRTOS_2

七、静态创建的优点

静态创建主要有三个优点:

  1. 不依赖运行期堆分配,任务创建更确定。
  2. 内存位置可控,可以把任务栈放到指定 RAM 区域。
  3. 内存占用更容易在编译期看清楚,适合可靠性要求高的工程。

它的代价也很明确:代码会更啰嗦,需要用户自己维护每个任务的 TCB 和任务栈。

八、常见注意点

  1. StaticTask_tStackType_t[] 必须具有静态生命周期,不能定义成普通局部变量。
  2. 栈大小单位是字,不是字节。
  3. 创建任务后要判断返回句柄是否为 NULL
  4. 删除静态任务不会释放用户提供的 TCB 和栈数组。
  5. 任务内部自己申请的资源,删除前仍然要主动释放。
  6. 如果启用了软件定时器,不要忘记实现定时器任务内存接口。

九、动态创建和静态创建的区别

对比项动态创建静态创建
创建函数xTaskCreate()xTaskCreateStatic()
TCB 来源FreeRTOS 从堆中申请用户提供 StaticTask_t
任务栈来源FreeRTOS 从堆中申请用户提供 StackType_t[]
创建失败原因可能因为堆不足失败不依赖堆,确定性更强
内存位置由堆管理决定用户可控
使用复杂度更简单更繁琐
常见场景普通应用内存确定性要求高的应用

十、小结

静态创建任务的本质,是把任务内存的分配权从 FreeRTOS 手里拿回来,由用户提前准备好 TCB 和任务栈。

记住四个点:

  1. xTaskCreateStatic() 用于静态创建任务。
  2. 静态任务的 TCB 和任务栈必须由用户提供。
  3. vTaskDelete() 也能删除静态任务,但不会释放用户提供的静态内存。
  4. 静态创建更确定,动态创建更简单。
文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇