3. 任务类型与调度策略选择

在 MICROSAR OS 中,任务(Task)是调度的基本单位,而任务类型与调度策略的选择,直接决定了系统的实时性、栈空间开销以及中断响应行为。很多配置错误并非出在优先级数值上,而是出在“任务类型选错了”或“抢占属性配反了”。本节把这两组维度拆开讲清楚,再给出混合场景下的选型依据。

一、基本任务与扩展任务:本质区别在“是否等待事件”

MICROSAR OS 遵循 AUTOSAR OS 规范,把任务分为基本任务(Basic Task)和扩展任务(Extended Task)两类。二者的核心差异只有一条:扩展任务可以调用 WaitEvent() 进入等待状态,基本任务不能。

由此派生出一系列连锁差异:

  • 状态机不同:基本任务只有就绪(Ready)、运行(Running)、挂起(Suspended)三态;扩展任务多出等待(Waiting)态。任务从运行态调用 WaitEvent() 后进入等待态,事件被 SetEvent() 置位后回到就绪态。
  • 栈空间不同:扩展任务在等待期间必须保留上下文,因此每个扩展任务需要独立私有栈;基本任务在终止后不保留上下文,多个基本任务可以共享同一栈区域(由 OsStack 配置决定)。这是扩展任务内存开销更大的根本原因。
  • 同步语义不同:扩展任务用“事件 + 等待”实现任务间同步,天然支持“生产者置事件、消费者等待”的解耦模型;基本任务只能靠激活(ActivateTask)或资源(Resource)来协调,无法在任务内部阻塞等待。
  • 终止行为不同:基本任务执行到函数末尾即自动终止;扩展任务必须显式调用 TerminateTask(),否则会报错。
判断口诀:任务内部是否需要“停下来等某个条件成立再继续”?需要 → 扩展任务;不需要、每次激活都跑完 → 基本任务。

二、抢占式与非抢占式:区别在“能否被更高优先级任务打断”

调度属性由任务配置中的调度策略决定,MICROSAR OS 支持三种取值:

调度策略行为典型用途
FULL(抢占式)更高优先级任务就绪时立即抢占当前任务硬实时控制、周期任务
NON(非抢占式)任务一旦运行,直到终止或主动让出才切换短小临界段、共享数据保护
MIXED(混合)任务内部通过 Schedule() 设置抢占点,仅在抢占点允许切换长任务中划分可抢占窗口

抢占式调度的优点是响应快,缺点是频繁上下文切换带来开销,且共享数据必须用资源(Resource)保护。非抢占式调度天然避免了任务级竞争,但会拉长高优先级任务的响应延迟——如果低优先级非抢占任务执行 2 ms,那么高优先级任务最坏要等 2 ms 才能运行。混合抢占则是在长任务中插入 Schedule() 调用,把任务切成若干可抢占片段,兼顾响应性与执行连续性。

三、调度关系与状态迁移可视化

下图把两类任务的状态机、抢占/非抢占的切换路径,以及混合调度中 Schedule() 的作用点放在同一张关系图里,便于对照理解。

任务状态迁移与调度策略关系图 基本任务(Basic Task) 挂起 就绪 运行 激活 调度 终止(自动) 无等待态 · 可共享栈 扩展任务(Extended Task) 挂起 就绪 运行 等待 激活 调度 WaitEvent SetEvent TerminateTask(显式) 有等待态 · 独立私有栈 调度策略对执行时序的影响 FULL 抢占式 低优先级任务运行中 高优先级抢占 恢复低优先级 NON 非抢占式 低优先级任务完整执行(高优先级就绪但等待) 高优先级运行 MIXED 混合 片段1 Schedule 片段2 仅在 Schedule() 处允许切换

四、混合调度场景下的选型依据

实际 ECU 中很少只用一种策略,常见的是“周期任务抢占式 + 短临界段非抢占式 + 长任务混合式”的组合。选型时按以下顺序判断:

  1. 先看实时性要求:硬实时周期任务(如 1 ms 电机控制环)必须用 FULL 抢占,保证截止期。若用 NON,一旦被低优先级任务阻塞,抖动不可控。
  2. 再看执行时长:任务最坏执行时间(WCET)远小于系统节拍(例如 < 100 µs)时,用 NON 反而更划算——省去上下文切换,且天然保护共享数据。WCET 较长(数百微秒以上)又需要响应中断时,改用 MIXED,在安全点插入 Schedule()。
  3. 再看同步需求:需要等待事件、需要与 ISR 解耦的,用扩展任务;纯计算、每次激活跑完即止的,用基本任务以节省栈。
  4. 最后看资源竞争:多个任务访问同一全局变量时,优先用 GetResource/ReleaseResource 保护,而不是简单把任务改成 NON——后者会引入优先级反转风险。

五、配置影响:改一个属性,动的是整条链

在 MICROSAR OS 的配置工具(如 EB tresos 或 DaVinci Configurator)中,任务属性集中在 OsTask 容器下。修改 OsTaskSchedule 或 OsTaskType 会引发以下连锁影响:

  • 栈空间:基本任务改扩展任务后,必须为其分配独立栈,OsStack 配置和链接脚本都要同步调整,否则运行时栈溢出。
  • 调度表:抢占式改非抢占式后,原本依赖抢占保证的响应时间需要重新核算,可能触发截止期违约。
  • 中断延迟:非抢占任务运行期间,任务级切换被禁止,但中断仍可响应(除非关中断)。若在非抢占任务中长时间关中断,会直接恶化中断延迟。
  • 优先级反转:非抢占任务持有资源时,高优先级任务只能等待,等效于把低优先级任务的执行时间加到高优先级任务上。
常见误区:把“非抢占”当成“不需要资源保护”。非抢占只保证任务级不切换,但 ISR 仍可能打断任务并访问同一数据,因此任务与 ISR 共享的数据依然需要临界区保护。

六、一个可参考的配置决策表

下表给出典型场景下的推荐组合,可作为配置起点,实际仍需结合 WCET 测量与响应时间分析调整。

场景任务类型调度策略理由
1 ms 电机控制环基本任务FULL硬实时,需立即抢占
10 ms 传感器采集基本任务FULL周期确定,WCET 短
100 ms 诊断通信扩展任务FULL需等待接收事件
共享数据写入(<50 µs)基本任务NON短临界段,避免切换开销
大块 Flash 擦写(>1 ms)基本任务MIXED长任务中插入抢占点
后台自检基本任务NON低优先级,可被延迟

配置完成后,务必用 Os_GetTaskState 或调度跟踪(如 ORTI 接口配合调试器)观察实际状态迁移,确认扩展任务确实进入了等待态、非抢占任务没有被意外抢占。只有状态迁移与设计意图一致,调度策略的选择才算真正落地。