在传统MCU开发中,我们经常会看到这样的启动过程:

上电 → Bootloader → 初始化硬件 → 启动RTOS → 创建Task → 进入主循环。

一个功能模块通常就是一个Task,一个项目最终也往往被编译成一个完整的固件镜像。

这种方式非常成熟,也非常适合资源有限、功能相对固定的嵌入式设备。

但如果一个MCU系统开始运行越来越多的软件功能,问题就来了:

一个应用究竟应该是什么?

它只是固件里的一个Task吗?

还是可以像Linux中的程序一样,有自己的启动、运行和退出过程?

这也是“独立应用层”真正值得讨论的地方。

望获OS近期发布的 zepLinux v0.6,基于Zephyr实时内核,并加入Linux命令行、虚拟文件系统、进程模型和独立应用层。相比传统RTOS把大量应用逻辑直接组织在固件中的方式,这实际上引入了一种更加接近现代操作系统的软件组织思路。

那么,一个独立应用到底经历了什么?从启动到退出,操作系统又需要承担哪些工作?

一、传统RTOS里的Task,为什么通常没有完整的“生命周期”概念?

先看最常见的RTOS开发方式。

假设我们开发一个工业控制设备,需要三个功能:

Sensor Task
   │
   ├── 采集传感器数据
   │
Control Task
   │
   ├── 执行控制算法
   │
Monitor Task
   │
   └── 状态监控

系统启动之后,初始化代码创建这些Task:

系统启动
   ↓
初始化硬件
   ↓
启动RTOS
   ↓
创建Task
   ↓
Task开始运行

之后每个Task进入自己的执行循环。

这种模式有一个非常明显的特点:

Task和整个固件是高度绑定的。

Sensor Task写在工程代码里,Control Task也写在工程代码里,Monitor Task同样如此。

如果修改其中一个功能,通常需要重新编译整个工程,再生成新的固件镜像。

因此,传统RTOS中的Task更多解决的是:

“系统里面有哪些并发执行的任务?”

而不是:

“系统里面有哪些可以独立管理的软件应用?”

这两者看起来很接近,实际上是两个不同层次的问题。

Task关注的是调度。

Application关注的是软件组织。

这也是为什么,当系统规模扩大以后,仅仅增加Task数量并不能自然解决软件复杂度问题。

二、Linux中的程序为什么可以“启动—运行—退出”?

再来看Linux。

在Linux系统中,我们打开一个程序,实际上发生了一系列操作:

用户执行程序
     ↓
操作系统找到程序
     ↓
创建进程
     ↓
建立运行环境
     ↓
加载程序
     ↓
开始执行
     ↓
程序运行
     ↓
退出
     ↓
系统回收资源

因此,一个应用程序具有比较明确的生命周期。

它不是系统启动时就必须永久存在的一个Task,而可以作为一个相对独立的软件实体存在。

例如:

System
 │
 ├── Application A
 │
 ├── Application B
 │
 └── Application C

A、B、C分别承担不同功能。

操作系统负责提供运行所需要的基础环境,而应用负责自己的业务逻辑。

这种软件组织方式最大的变化,并不是“启动程序更方便”。

真正的变化是:

应用开始从系统代码中获得相对独立的软件身份。

这会直接影响开发、测试、调试以及后续维护。

例如一个设备已经完成底层系统开发,后续需要增加一个数据处理应用。

传统方式往往是:

修改工程
 ↓
重新编译
 ↓
重新生成固件
 ↓
重新烧录
 ↓
重新验证

而采用独立应用层之后,理论上可以形成更加清晰的边界:

底层系统
   │
   ├── RTOS
   ├── 驱动
   ├── 系统服务
   │
   └── 应用运行环境
           │
           ├── App A
           ├── App B
           └── App C

当然,这并不意味着任何采用“独立应用层”的RTOS都天然支持Linux式的软件安装、动态加载或者在线升级。

具体能力仍然取决于操作系统的实际实现。

这里需要把“独立应用”与“动态程序加载”区分开。

独立应用首先解决的是软件边界和组织方式,而不是简单等同于某一种加载技术。

三、zepLinux为什么要强调“独立应用层”?

这就回到zepLinux v0.6。

根据目前公开的版本介绍,zepLinux并没有选择直接把完整Linux运行环境搬到MCU上,而是以Zephyr实时内核作为基础,并进一步引入Linux命令行、虚拟文件系统、进程模型和独立应用层。

这几个能力实际上是相互关联的。

可以把它理解成:

                 zepLinux
                    │
       ┌────────────┴────────────┐
       │                         │
   实时内核能力              Linux Style
       │                         │
    Zephyr                 Shell / VFS
                              │
                         Process Model
                              │
                       Independent Apps

Zephyr解决的是底层实时操作系统问题。

Shell提供更加接近Linux的命令行交互方式。

VFS提供统一的文件系统抽象。

Process Model提供应用层的软件组织方式。

Independent Application Layer则进一步明确:

应用不必再简单等同于固件内部的一组Task。

这对于MCU来说非常重要。

因为未来的MCU软件可能不再只是一个固定功能的控制程序,而可能同时包含:

设备控制、数据采集、网络通信、边缘计算、协议解析、状态监测等多个功能模块。

如果所有功能都直接堆叠在一个固件工程里,那么软件之间的耦合会越来越严重。

而独立应用层的意义,就是尝试把这种复杂度重新拆开。

例如:

┌────────────────────────────┐
│          zepLinux           │
│                            │
│  RTOS / Driver / System    │
├────────────────────────────┤
│       Independent Apps     │
│                            │
│  App A  │  App B  │ App C  │
└────────────────────────────┘

这样,系统层和应用层的职责会更加清晰。

系统负责提供基础能力。

应用负责实现具体功能。

应用之间通过约定的接口进行协作。

这也是前面文章讨论IPC时所提到的一个重要变化:当应用边界变得清晰之后,应用之间如何通信、如何启动、如何退出,也会成为操作系统需要解决的问题。

四、一个真正的“应用生命周期”,操作系统需要做什么?

如果进一步抽象,一个完整的应用生命周期至少可以拆成几个阶段:

          应用程序
             │
             ▼
          启动准备
             │
             ▼
          创建运行环境
             │
             ▼
            运行
             │
       ┌─────┴─────┐
       │           │
     正常退出    异常退出
       │           │
       └─────┬─────┘
             ▼
          资源回收

这背后实际上涉及很多操作系统基础能力。

第一是启动。

系统需要识别应用,并为其提供运行所需要的环境。

第二是运行。

应用需要获得CPU执行时间,同时使用文件、设备、通信等系统资源。

第三是通信。

应用可能需要和其他应用交换数据,这就涉及消息、共享内存、IPC等机制。

第四是退出。

应用正常结束之后,操作系统需要处理它占用的资源。

第五是异常处理。

如果一个应用出现错误,系统需要考虑这个错误是否会影响其他应用。

这里就能看到,所谓“独立应用”,实际上并不是简单把程序文件拆出来。

它背后对应的是一整套操作系统能力:

应用
 │
 ├── 启动
 ├── 调度
 ├── 资源访问
 ├── IPC
 ├── 退出
 └── 异常处理
       │
       ▼
     操作系统

这也是为什么,zepLinux的技术路线值得从“软件架构”而不仅仅是“功能列表”的角度去理解。

它尝试解决的不是单独某一个命令、某一个文件系统功能,而是:

如何在MCU这样资源受限的平台上,建立一种更加接近现代操作系统的应用运行模型。

五、从“一个固件”走向“一个系统+多个应用”,MCU软件正在发生什么变化?

如果把前面的内容串起来,就能看到一个比较清晰的变化。

传统RTOS更典型的开发方式是:

              一个固件
                 │
      ┌──────────┼──────────┐
      │          │          │
    Task A     Task B     Task C
      │          │          │
      └──────共享系统资源─────┘

这种架构简单、高效,也非常适合很多实时控制设备。

而当系统越来越复杂之后,可以进一步思考:

             操作系统
                 │
       ┌─────────┴─────────┐
       │                   │
     系统层              应用层
       │                   │
 RTOS / Driver       App A / App B
       │                   │
       └────── IPC ────────┘

这不是说后者一定要替代前者。

真正的变化是:MCU上的软件开始有机会从“固件思维”向“操作系统思维”演进。

这也是zepLinux v0.6提出“Linux Style RTOS”这一概念值得关注的原因。

它保留Zephyr作为实时内核基础,同时增加Linux命令行、虚拟文件系统、进程模型和独立应用层。

最终形成的并不是一个“缩小版Linux”,而是一种针对MCU资源条件重新组织的软件架构。

对于工业控制、机器人、智能设备、边缘计算等场景来说,这种架构可能带来的最大价值,并不是让MCU“看起来更像Linux”,而是让越来越复杂的软件功能能够拥有更加清晰的边界。

从这个角度看,独立应用层只是第一步。

当应用能够独立存在之后,接下来真正值得研究的问题就会变成:

应用如何被系统发现?

如何加载和启动?

如何进行权限和资源管理?

应用之间如何通信?

一个应用发生异常时,如何避免影响整个系统?

这些问题,最终都会回到一个更基础的主题:

MCU上的RTOS,正在从“任务调度器”逐渐走向“应用运行平台”。

而这或许正是zepLinux这类Linux Style RTOS值得继续观察的地方。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐