【FreeRTOS】任务(TASK)——任务的创建(源码解读)
在FreeRTOS中,任务可以被理解为一个独立运行的函数,它拥有自己的栈空间和程序计数器,可以与其他任务并发执行。每个任务都拥有唯一的优先级,优先级高的任务会优先获得CPU资源。任务(Task) 是系统调度的基本单元,其本质是一个独立的执行线程。
【FreeRTOS】任务(TASK)——定义、切换、管理
一、任务的创建方式
FreeRTOS 提供两种任务创建方式,分别对应不同的内存管理策略:
动态创建 | 静态创建 | |
---|---|---|
内存分配 | 由 FreeRTOS 堆动态分配 TCB 和栈空间 | 用户预先提供 TCB 和栈内存 |
适用场景 | 任务数量不确定、内存管理灵活 | 资源受限、需严格内存控制 |
优点 | 简单易用,无需手动管理内存 | 无堆内存碎片,确定性更高 |
缺点 | 容易产生内存碎片 | 需手动分配内存,灵活性低 |
配置开关 | configSUPPORT_DYNAMIC_ALLOCATION=1 | configSUPPORT_STATIC_ALLOCATION=1 |
二、任务创建 API 函数解析
2.1 动态创建函数 xTaskCreate()
BaseType_t xTaskCreate(
TaskFunction_t pvTaskCode, // 任务函数指针
const char * const pcName, // 任务名称(字符串,用于调试)
configSTACK_DEPTH_TYPE usStackDepth, // 栈大小(单位:字)
void *pvParameters, // 任务参数(传递给任务函数的 void* 指针)
UBaseType_t uxPriority, // 初始优先级
TaskHandle_t *pxCreatedTask // 任务句柄输出(可设为 NULL)
);
返回值 | 含义 |
---|---|
pdPASS | 任务创建成功 |
errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY | 内存不足,创建失败 |
2.2 静态创建函数 xTaskCreateStatic()
TaskHandle_t xTaskCreateStatic(
TaskFunction_t pxTaskCode, // 任务函数指针
const char * const pcName, // 任务名称
uint32_t ulStackDepth, // 栈大小(单位:字)
void *pvParameters, // 任务参数
UBaseType_t uxPriority, // 初始优先级
StackType_t *pxStackBuffer, // 用户提供的栈内存数组
StaticTask_t *pxTaskBuffer // 用户提供的 TCB 内存
);
返回值: 任务句柄(若参数无效返回 NULL)。
三、任务创建函数 源码解析
下载源码可从FreeFtos官网直接下载,我下载的是FreeRTOSv202406.01-LTS版本
FreeRTOS™
2.1 动态创建函数 xTaskCreate()
函数原型
/*-----------------------------------------------------------*/
/* 函数定义:xTaskCreate
* 返回值:BaseType_t(FreeRTOS标准返回类型,成功或错误码)
* 参数说明见下方详细注释 */
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, // 任务函数指针(函数入口)
const char * const pcName, // 任务名称字符串(用于调试)
const configSTACK_DEPTH_TYPE uxStackDepth, // 任务堆栈深度(单位:字)
void * const pvParameters, // 传递给任务的参数指针
UBaseType_t uxPriority, // 任务优先级
TaskHandle_t * const pxCreatedTask ) // 输出任务句柄
{
TCB_t * pxNewTCB; // 定义任务控制块(TCB)指针
BaseType_t xReturn; // 函数返回值变量
/* FreeRTOS调试跟踪宏,记录函数调用信息(需开启configUSE_TRACE_FACILITY) */
traceENTER_xTaskCreate( pxTaskCode, pcName, uxStackDepth, pvParameters, uxPriority, pxCreatedTask );
/* 调用私有函数prvCreateTask,完成TCB和堆栈内存分配、初始化工作 */
pxNewTCB = prvCreateTask( pxTaskCode, // 传递任务函数
pcName, // 传递任务名称
uxStackDepth, // 传递堆栈深度
pvParameters, // 传递参数指针
uxPriority, // 传递优先级
pxCreatedTask ); // 传递任务句柄指针
/* 检查TCB是否分配成功 */
if( pxNewTCB != NULL ) // 内存分配成功
{
/* 条件编译:多核CPU亲和性设置(仅当configNUMBER_OF_CORES > 1且启用亲和性时生效) */
#if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) )
{
/* 设置任务的CPU核心亲和性掩码(例如0x01表示仅允许在核心0运行) */
pxNewTCB->uxCoreAffinityMask = configTASK_DEFAULT_CORE_AFFINITY;
}
#endif
/* 将新任务添加到就绪列表(Ready List),准备被调度 */
prvAddNewTaskToReadyList( pxNewTCB );
xReturn = pdPASS; // 返回成功标志
}
else // 内存分配失败(TCB或堆栈分配失败)
{
xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; // 返回内存错误码
}
/* FreeRTOS调试跟踪宏,记录函数返回信息 */
traceRETURN_xTaskCreate( xReturn );
return xReturn; // 返回函数结果(pdPASS或错误码)
}
/*-----------------------------------------------------------*/
函数执行流程
-
调试跟踪入口
调用traceENTER_xTaskCreate
,用于调试或跟踪任务创建过程(通常由宏定义实现,可能记录任务创建事件)。 -
创建任务控制块(TCB)和栈空间
调用prvCreateTask
函数完成核心工作:- 内存分配:为任务的 TCB(Task Control Block) 和 栈空间 分配内存。
- 初始化TCB:设置任务函数指针、栈指针、参数、优先级、状态等关键字段。
- 返回TCB指针:成功时返回
pxNewTCB
,失败返回NULL
。
-
多核亲和性设置(条件编译)
如果系统配置为多核(configNUMBER_OF_CORES > 1
)且启用核心亲和性(configUSE_CORE_AFFINITY == 1
):- 设置任务的默认核心亲和性掩码
pxNewTCB->uxCoreAffinityMask
(例如0x01
表示绑定到核心0)。
- 设置任务的默认核心亲和性掩码
-
将任务加入就绪列表
调用prvAddNewTaskToReadyList(pxNewTCB)
:- 根据优先级将任务插入 就绪列表(Ready List)。
- 如果新任务优先级高于当前运行任务,可能触发上下文切换(需调度器已启动)。
-
返回值处理
- 成功(
pxNewTCB != NULL
):返回pdPASS
。 - 失败(内存不足):返回
errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY
。
- 成功(
-
调试跟踪出口
调用traceRETURN_xTaskCreate
,记录函数返回结果。
关键代码分析
1. prvCreateTask
内部逻辑
- 内存分配:从堆中分配
TCB + 栈空间
,若内存不足返回NULL
。 - 栈初始化:使用
pxPortInitialiseStack
初始化栈帧,模拟任务首次运行的上下文。 - 任务链表:将新任务的TCB加入任务链表,维护任务状态。
2. 多核亲和性
- 掩码机制:通过位掩码指定允许运行的核心(例如
0b011
允许核心0和1)。 - 调度策略:调度器根据亲和性掩码选择合适核心运行任务(需配合调度算法)。
3. 就绪列表管理
- 优先级排序:任务按优先级排列在就绪列表中,同优先级任务可能采用轮转调度。
- 调度触发:若新任务优先级高于当前任务,可能触发
portYIELD()
请求上下文切换。
错误处理
- 内存不足:
prvCreateTask
返回NULL
,函数返回errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY
。 - 栈溢出风险:需合理设置
uxStackDepth
,可通过uxTaskGetStackHighWaterMark
监控栈使用。
使用示例
void vTaskFunction(void *pvParameters) {
// 任务逻辑
}
TaskHandle_t xHandle;
xTaskCreate(
vTaskFunction, // 任务函数
"Task1", // 任务名
128, // 栈深度(字)
NULL, // 参数
1, // 优先级
&xHandle // 任务句柄
);
总结
xTaskCreate
是 FreeRTOS 任务创建的核心函数,负责:
- 分配资源(TCB、栈)
- 初始化任务上下文
- 设置多核亲和性(可选)
- 将任务加入调度队列
- 返回创建状态
其设计体现了轻量级实时操作系统的特点,通过条件编译支持多核扩展,同时保持单核系统的高效性。