欢迎光临
我们一直在努力

Classic AUTOSAR深入浅出系列 - 【第六篇A】 AUTOSAR OS:调度的是 Task,运行的是 Runnable

  • 4-A 篇:
    👉 更偏「OS 是什么、官方机制有哪些、为什么这么设计」
  • 本篇(第 6 篇):
    👉 OS 在工程里到底怎么“被用”,以及 Runnable 到底是怎么落在 Task 里的
    在这里插入图片描述

6️⃣ AUTOSAR OS:调度的是 Task,运行的是 Runnable

【Operating System】


一、先把一句最容易被误解的话说清楚

在 AUTOSAR 项目里,经常能听到一句话:

“OS 调度的是 Task,应用跑的是 Runnable。”

这句话方向是对的,但如果只停在这句话,99% 的新手都会理解错。

我们先用一句更工程化的说法替换它:

AUTOSAR OS 只认识 Task / ISR / Alarm / ScheduleTable
Runnable 是通过 RTE,被“塞进”某个 Task 里执行的普通 C 函数。

Runnable 不是 OS 的对象。
Runnable 也不参与调度决策。

这一点,是理解后面所有内容的地基。


二、AUTOSAR OS 的几个“默认前提”(非常接地气版)

AUTOSAR OS 并不是“万能 RTOS”,它的设计前提非常明确,甚至有点“偏执”。

1️⃣ 没有动态创建,一切都是“先配好”

在 AUTOSAR OS 里:

  • Task 数量:配置时就固定

  • 优先级:配置时就固定

  • Alarm / ScheduleTable:配置时就固定

  • 没有:

    • xTaskCreate
    • pthread_create
    • 运行期随意拉起新线程

工程后果很直接:

如果你运行时才发现“少了一个 Task”,
那不是 OS 的问题,是你架构没想清楚。


2️⃣ OS 不关心“你在 Task 里干了什么”

对 OS 来说:

  • Task 是一个 entry function

  • Task 里跑什么逻辑 ——

    • 是 Runnable
    • 还是直接写的 C 代码
      OS 完全不关心

这也是为什么:

  • Runnable 不在 OS 规范里定义
  • Runnable 是 Application + RTE 的概念

3️⃣ OS 的世界观非常简单

AUTOSAR OS 的“宇宙”里只有四类核心对象:

对象干什么的
Task 被调度执行的基本单位
ISR 中断入口
Alarm 基于 Counter 的定时触发器
ScheduleTable 一组“时间点 + 动作”的序列

没有线程池、没有 Future、没有 Event Loop。


三、Task:OS 世界里真正被调度的东西

3.1 Task 是什么(工程视角)

从代码角度看,Task 本质就是:

TASK(Task_10ms)
{
/* RTE 或手写代码 */
TerminateTask();
}

OS 关心的只有几件事:

  • Task 什么时候 Ready
  • Task 优先级
  • Task 是 Basic 还是 Extended
  • Task 会不会主动等待 Event

3.2 Basic Task vs Extended Task(不要背定义)

在 Classic AUTOSAR 里,Task 是 OS 唯一调度单位。Runnable 只是 被调度执行的函数,它永远不会被 OS 直接看见。而在所有 Task 类型中,Extended Task 是最容易被“概念化误用”的。这一节,我们将用较长篇幅阐述他们的区别和使用case。

很多工程里会出现这样的情况:

“这个 Task 要等事件,用 Extended Task 吧。”
“这个 Runnable 要阻塞一下,用 Extended Task 吧。”
“这个 Task 里有等待条件,肯定得 Extended。”

结果是:
👉 Extended Task 被当成“高级 Task”
👉 系统复杂度上升,但收益为 0
👉 调度时序反而更难分析

这一节,我们只回答三个问题:

  • Extended Task 到底“多了什么能力”?
  • 它解决的是什么真实问题?
  • 在 Runnable 视角下,什么时候“必须”用 Extended Task?

  • 3.2.1 先说结论:90% 的 Task 都不该是 Extended

    在绝大多数量产 Classic AUTOSAR 项目中:

    • 周期任务 → Basic Task
    • 纯计算 / 状态更新 → Basic Task
    • 信号处理 / 通信接收回调 → Basic Task
    • RTE 触发 Runnable → Basic Task

    Extended Task 的真实使用场景非常窄。

    它不是为了“更复杂逻辑”,而是为了**“等待某个 OS Event”**。

    ⚠️ 重点:
    Extended Task ≠ 能跑得更久 / 更复杂
    Extended Task = 可以 Sleep,直到 Event 到来


    3.2.2 不讲定义,直接看“能力差异”

    我们不用规范语言,直接用行为差异来对比。

    能力点Basic TaskExtended Task
    能否 WaitEvent ❌ 不行 ✅ 唯一能
    能否被多次激活 ❌(激活合并) ❌(同样)
    是否允许阻塞 ✅(但仅限 Event)
    是否适合周期调度 ✅ 非常适合 ❌ 非常不适合
    是否适合 Runnable ✅ 绝大多数 ⚠️ 极少数

    一句话总结:

    Extended Task 的全部存在意义 = WaitEvent / ClearEvent / SetEvent

    如果你没有用到这三个 API,
    那你用 Extended Task 一定是错的。


    3.2.3 一个“错误但常见”的 Extended Task 用法

    我们先看一个你一定见过的反例。

    ❌ 错误示例:用 Extended Task 跑周期 Runnable

    TASK(Task_10ms)
    {
    Rte_Run_Task_10ms();
    TerminateTask();
    }

    配置:

    TaskType = EXTENDED
    Priority = 5
    Schedule = FULL

    理由通常是:

    • “以后可能要加 WaitEvent”
    • “Extended 比 Basic 高级一点”
    • “模板就是这么生成的”

    👉 这是典型的“概念驱动配置”,不是系统设计

    问题在哪里?

    • 没有 WaitEvent
    • 没有 Event
    • 没有阻塞需求
    • 却引入了 Extended Task 的调度语义复杂性

    这类 Task 100% 应该是 Basic Task。


    3.2.4 那 Extended Task 到底是为谁准备的?

    答案很简单,但很多人没意识到:

    Extended Task 是为“异步事件源 + 主动等待模型”准备的

    它解决的是这一类问题:

    • 事件不是周期性的
    • 事件到来之前,Task 不应该占用 CPU
    • Task 需要“睡眠 → 唤醒 → 处理 → 再睡眠”

    3.2.5 一个正确、典型、工程级的 Extended Task 场景

    场景:通信栈里的“事件驱动处理线程”

    比如某些 SoAd / TcpIp / CDD 场景:

    • 底层 ISR 收到数据
    • ISR 不适合做复杂处理
    • 希望在 Task 上下文中处理
    • 但不希望轮询

    这时,Extended Task 就是唯一正确解法。


    Step 1:Extended Task 主循环

    TASK(Task_ComEvent)
    {
    while (1)
    {
    WaitEvent(EV_RX | EV_TX | EV_TIMEOUT);
    EventMaskType ev;
    GetEvent(Task_ComEvent, &ev);

    if (ev & EV_RX)
    {
    ClearEvent(EV_RX);
    HandleRxData();
    }

    if (ev & EV_TX)
    {
    ClearEvent(EV_TX);
    HandleTxData();
    }
    }
    }

    这里有几个关键点:

    • Task 不会退出
    • WaitEvent() 会让 Task 挂起
    • OS 调度器 不会再考虑它
    • 直到某个 Event 被 Set

    Step 2:Event 的来源

    Event 通常来自:

    • ISR
    • Alarm
    • 其他 Task

    例如 ISR:

    void Rx_ISR(void)
    {
    SetEvent(Task_ComEvent, EV_RX);
    }

    这才是 Extended Task 的原生用法。


    3.2.6 为什么 Runnable 几乎不该跑在 Extended Task 里?

    这是非常重要的一点。

    原因一:Runnable 语义是“快速、确定性执行”

    RTE 假设 Runnable:

    • 不阻塞
    • 不 Sleep
    • 执行时间可控
    • 可被周期性触发

    而 Extended Task 的语义是:

    • 可能无限等待
    • 执行时间不可预测
    • 生命周期不是“一次执行”

    👉 两者是天然不匹配的


    原因二:RTE 生成代码不会帮你处理 Event

    RTE 生成的典型 Task 入口是:

    TASK(Task_10ms)
    {
    Rte_Run_Task_10ms();
    TerminateTask();
    }

    它:

    • 不知道 Event
    • 不知道 WaitEvent
    • 不知道 Task 是否会再回来

    如果你把 Runnable 塞进 Extended Task:

    • 要自己包循环
    • 要自己管理 Event
    • 要自己保证 Runnable 不被重复调用

    👉 这已经脱离 RTE 的设计边界


    3.2.7 Extended Task 的“隐藏成本”

    很多人只看到它“能等事件”,却忽略了代价。

    1️⃣ 调度分析复杂度陡增
    • Task 不再是“来 → 跑 → 走”
    • 而是“睡着 → 被唤醒 → 不确定跑多久”

    对:

    • 响应时间分析
    • Worst Case Execution Time
    • 系统负载估算

    都是灾难级影响。


    2️⃣ 极易引入“忘 ClearEvent”的死锁

    这是 Extended Task 最常见 Bug:

    WaitEvent(EV_RX);
    HandleRxData();
    // 忘了 ClearEvent

    结果:

    • Task 永远不再 Wait
    • 一直被 OS 认为 Ready
    • CPU 被“吃死”

    3️⃣ 与 BswM / Mode 切换协作困难

    Extended Task:

    • 不会自然退出
    • 不会自然响应 Mode 切换
    • 必须额外设计退出 / 禁用机制

    而 Basic Task:

    • Mode 切换 = 不再 Activate
    • 天然干净

    3.2.8 给工程师的“是否该用 Extended Task”检查表

    你在配置 Task 前,可以问自己这 5 个问题:

  • 是否需要 WaitEvent?
  • 是否需要在 Task 内 Sleep?
  • 是否不适合用 Alarm / ScheduleTable?
  • 是否明确知道 Event 从哪里 Set?
  • 是否接受调度分析复杂化?
  • 只要有一条是否定的:

    👉 不要用 Extended Task


    3.2.9 一句话工程结论

    Basic Task 是 Classic AUTOSAR 的主力部队
    Extended Task 是特种兵,只在极少数场景出动

    如果你在一个项目里看到:

    • 80% Task 是 Extended
    • Runnable 全跑在 Extended Task
    • 却没有一个 WaitEvent

    那几乎可以肯定:

    👉 这个 OS 设计是“配置驱动的”,不是“系统驱动的”


    3.3 Task 优先级:不要想得太“算法化”

    很多人一开始就问:

    “优先级要怎么规划?要不要像 Linux 一样精细?”

    现实答案是:

    • AUTOSAR 项目里
    • Task 数量有限
    • 优先级通常是“分层”的,而不是“精细排序”

    一个常见分法:

    优先级层级示例
    中断后处理 / 通信关键路径
    周期控制任务
    诊断 / 记录 / 非实时

    四、ISR:中断不是你想写多少就写多少

    4.1 AUTOSAR 里的 ISR 分两类

    • Category 1 ISR

      • OS 不管理
      • 非常少用
    • Category 2 ISR

      • OS 感知

      • 可以:

        • 激活 Task
        • SetEvent
        • 增加 Counter

    实际项目:99% 用的是 Cat2 ISR


    4.2 ISR 里千万别干的事

    工程里踩坑最多的几条:

    • ❌ 在 ISR 里跑 Runnable
    • ❌ 在 ISR 里做复杂逻辑
    • ❌ 在 ISR 里访问 NvM / DCM

    正确姿势:

    ISR 只负责“通知”,
    具体处理交给 Task。


    五、Alarm:很多人一辈子都“半懂不懂”

    5.1 Alarm 到底是什么?

    一句话:

    Alarm = Counter 到点后,自动执行一个 OS 动作

    这个动作可以是:

    • ActivateTask
    • SetEvent
    • IncrementCounter(链式)

    5.2 一个最常见的 10ms 周期例子

    配置逻辑(概念化):

    • Counter:SystemCounter(1ms tick)

    • Alarm_10ms:

      • Offset = 10
      • Cycle = 10
      • Action = ActivateTask(Task_10ms)

    运行时效果:

    每 10ms
    → Counter++
    → Alarm 到点
    → Task_10ms Ready

    注意:

    • Alarm 本身不执行代码
    • 它只是“拉起 Task”

    5.3 Alarm 和 Runnable 的关系(非常容易错)

    ❌ 错误理解:

    Alarm 触发 Runnable

    ✅ 正确理解:

    Alarm → ActivateTask → Task → Runnable


    六、ScheduleTable:比 Alarm 更“工程友好”的东西

    6.1 为什么要有 ScheduleTable?

    当你有这种需求时:

    • 0ms:Task_A
    • 5ms:Task_B
    • 10ms:Task_C
    • 20ms:循环

    如果全用 Alarm:

    • 配一堆 Alarm
    • 很难维护
    • 时序不直观

    ScheduleTable 的优势是:

    把“时间轴”本身变成配置对象


    6.2 ScheduleTable 长什么样(概念)

    Time 0ms → ActivateTask(A)
    Time 5ms → ActivateTask(B)
    Time 10ms → ActivateTask(C)


    七、Runnable:它不是 OS 的“孩子”

    7.1 Runnable 到底是什么?

    Runnable:

    • 是 Application 层的函数
    • 由 RTE 生成调用入口
    • 本质就是一个 C 函数

    void Runnable_EngineCtrl(void)
    {
    /* 业务逻辑 */
    }


    7.2 Runnable 怎么“跑”起来的?

    关键链路只有一条:

    OS Task
    → RTE 调度代码
    → Runnable()

    Runnable 永远不会:

    • 被 OS 直接调度
    • 被 Alarm 直接触发
    • 被 ISR 直接调用

    八、Runnable 映射 Task:最容易踩坑的地方

    8.1 多个 Runnable 映射到一个 Task(最常见)

    Task_10ms:
    – Runnable_A
    – Runnable_B
    – Runnable_C

    执行顺序:

    • 固定
    • 由 RTE 生成代码决定
    • 不是并发

    8.2 一个 Runnable 映射多个 Task(谨慎)

    • 不同周期
    • 不同触发条件

    风险点:

    • 重入
    • 数据一致性
    • Exclusive Area 配置

    九、 4-A OS 深入解析的区别说明

    维度4-A 那篇本篇
    目标 OS 原理 OS 怎么被用
    重心 规范机制 工程映射
    Runnable 原理解释 实际落点
    配置

    这两篇是互补关系,不是重复。


    十、总结

    • OS 只调度 Task

    • Alarm / ScheduleTable 只会“拉 Task”

    • Runnable 永远躲在 Task 后面

    • 90% 的问题:

      • Task 划分不合理
      • Runnable 映射没想清楚
      • ISR 干了不该干的事

    赞(0)
    未经允许不得转载:171主机测评 » Classic AUTOSAR深入浅出系列 - 【第六篇A】 AUTOSAR OS:调度的是 Task,运行的是 Runnable
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址