结论
任务的运行顺序 和 创建顺序 没有任何关系! FreeRTOS 是抢占式调度器,任务执行顺序只由 2 个规则决定:
- 优先级高的任务 → 永远先运行(核心规则)
- 同优先级任务 :新创建的任务会立即抢占当前任务 ,直接导致后创建、先运行
原理(FreeRTOS 调度核心机制)
1. 抢占式调度器(最重要)
FreeRTOS 默认开启 抢占式调度:
- 只要有更高优先级 的任务进入就绪态,CPU 会立刻停止当前任务,去运行高优先级任务
- 优先级:数值越大,优先级越高(CMSIS-V2 / STM32CubeMX 配置)
2. 同优先级任务的规则
创建的任务优先级完全相同 (都是 osPriorityNormal):
- 同优先级任务默认使用 时间片轮转调度
- 新创建的任务 会被插入到就绪链表的头部
- 调度器会立即切换 到这个新任务运行→ 表现为:谁后创建,谁先抢 CPU 运行
3. 补充:调度器启动前创建任务
如果在 vTaskStartScheduler() 之前创建所有任务:
- 所有任务排队进入就绪链表
- 调度器启动后,运行最高优先级任务
- 同优先级:运行链表第一个任务(先创建的先运行)
运行机制
cpp
// 都是 osPriorityNormal 同优先级
xTaskCreate(Input_Task, ...); // 先创建
xTaskCreate(platform_task, ...); // 后创建
执行流程:
- CPU 正在运行
game1_task - 调用
xTaskCreate创建platform_task - 新任务优先级 = 当前任务优先级
- FreeRTOS 直接抢占切换 :暂停
game1_task,先运行platform_task - 所以你看到:后创建的任务先运行
可复制验证代码(直观看到效果)
cpp
// 三个同优先级任务
void Task1(void *p)
{
while(1)
{
LCD_PrintString(0,0,"Task1 Run");
vTaskDelay(500);
}
}
void Task2(void *p)
{
while(1)
{
LCD_PrintString(0,2,"Task2 Run"); // 后创建,会先打印!
vTaskDelay(500);
}
}
void game1_task(void *params)
{
// 先创建 Task1
xTaskCreate(Task1, "Task1", 128, NULL, osPriorityNormal, NULL);
// 后创建 Task2
xTaskCreate(Task2, "Task2", 128, NULL, osPriorityNormal, NULL);
while(1)
{
vTaskDelay(100);
}
}
✅ 现象:LCD 先显示 Task2 Run,验证后创建先运行
避坑提醒(STM32F103 + FreeRTOS 专属)
-
绝对不要依赖「任务创建顺序」控制执行流程 同优先级任务的执行顺序是不确定的,换芯片 / 升级库可能失效
-
需要优先运行的任务 → 提高优先级例:平台控制任务需要优先运行
// 高优先级 xTaskCreate(platform_task, ..., osPriorityAboveNormal, NULL); // 普通优先级 xTaskCreate(Input_Task, ..., osPriorityNormal, NULL); -
业务同步不要靠执行顺序 用 队列、任务通知、互斥锁、信号量 做任务同步(你项目中已用队列,正确)
-
抢占式调度默认开启这是 FreeRTOS 标准配置,不要关闭,否则系统实时性崩溃