| 上一篇 | 下一篇 |
|---|---|
| 任务创建和删除 相关的 API 函数 |
"任务创建" 和 "堆栈" 的动静态区分
注意:动态分配内存不是说连内存大小都能自动判断的,任务堆栈大小仍然是要作为输入参数人为给出的。
在一开始介绍任务的动静态创建方式时,大家或许会有一些疑问,这里的动静态貌似和堆栈的动静态内存分配相反了(C 语言中,栈是静态分配/自动分配,堆是动态分配),其实这只是表面上看似乎"反着来"了。但这是术语在不同上下文中的应用导致的错觉。
关键在于区分:
- 内存分配的时机和方式(编译时 vs 运行时)
- 内存本身的用途(是用作栈空间,还是其他)
① 核心概念:什么是"静态"和"动态"
在 C 语言和嵌入式系统中,"静态"和"动态"通常指的是内存分配的时间和管理方式:
- 静态分配 (Static Allocation) :
- 内存是在编译时或链接时就确定的。
- 内存通常来自程序的
.data(已初始化全局/静态变量)或.bss(未初始化全局/静态变量)段。 - 程序员手动定义变量,内存由编译器/链接器安排,不需要调用
malloc或类似函数。 - 生命周期长,通常是全局的或
static的。
- 动态分配 (Dynamic Allocation) :
- 内存是在程序运行时 通过调用库函数(如
malloc,free,pvPortMalloc,vPortFree)来申请和释放的。 - 内存来自一个被称为"堆"(heap)的区域。
- 分配和释放的时间不固定,由程序员在代码中控制。
- 内存是在程序运行时 通过调用库函数(如
② FreeRTOS 任务创建的两种方式
1. 动态创建 xTaskCreate()
c
// 示例
xTaskCreate(vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
- 发生了什么?
- 当你调用
xTaskCreate()时,FreeRTOS 内核会在函数内部调用pvPortMalloc()(FreeRTOS 版本的malloc)。 - 这个
malloc调用会从 FreeRTOS 管理的堆 (heap) 中动态地分配两块内存:- 一块用于存放 任务控制块 (TCB - Task Control Block)。
- 一块用于作为该任务的 栈空间 (Stack Space)。
- 当你调用
- 为什么叫"动态"?
- 因为这两块内存的分配发生在运行时 ,通过
malloc类函数完成。 - 你不需要提前准备内存,FreeRTOS 在你需要时自动从堆里"动态"地拿。
- 因为这两块内存的分配发生在运行时 ,通过
- 内存用途 :这块动态分配的内存 ,其中一部分被用作任务的栈。
2. 静态创建 xTaskCreateStatic()
c
// 提前定义好内存
StaticTask_t xTaskBuffer; // 用于 TCB
StackType_t xStack[STACK_SIZE]; // 用于栈空间
// 创建任务
xTaskCreateStatic(vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, xStack, &xTaskBuffer);
- 发生了什么?
- 你提前在代码中定义了两个变量:
xTaskBuffer:一个StaticTask_t类型的变量,它本身就是一个结构体,用来存放 TCB。xStack:一个StackType_t数组,用来存放任务的栈数据。
- 当你调用
xTaskCreateStatic()时,你把这两个变量的地址传给 FreeRTOS。 - FreeRTOS 直接使用你提供的内存,不再调用
malloc。
- 你提前在代码中定义了两个变量:
- 为什么叫"静态"?
- 因为你提供的内存(
xTaskBuffer和xStack)是在编译时就确定大小和位置的。 - 它们通常是全局变量或
static变量,存储在.bss或.data段。 - 分配发生在程序启动前,是"静态"的。
- 因为你提供的内存(
③ 为什么感觉"反着来"?
咱们感觉到的"反着来",很可能是因为混淆了 内存分配的方式 和 内存的用途。表面上好像是:"栈"不是应该在栈上吗?栈上的内存不是"静态"或自动分配的吗?
实际是 :在 FreeRTOS 中,每个任务都有自己的私有栈空间 。关键问题是:这块用于"栈功能"的内存区域,是如何被分配的?
| 任务创建方式 | 用于"栈功能"的内存如何分配? | 用于"TCB"的内存如何分配? |
|---|---|---|
| 动态创建 | 从 堆 (heap) 中 动态 (malloc) 分配 |
从 堆 (heap) 中 动态 (malloc) 分配 |
| 静态创建 | 由用户静态定义(如全局数组)提供 | 由用户静态定义(如全局结构体)提供 |
所以,"动态"和"静态"描述的是TCB 和栈空间这两块内存的获取方式,而不是指任务运行时使用的"栈机制"本身。