一般看《计算机操作系统》的书籍,都会有进程(Process),线程(Thread)的概念。但是在嵌入式RTOS里面,比如应用于汽车软件的OSEK/VDX Operating System Specification 2.2.3规范里没有这两个概念,有的是任务(Task)。那么这三个概念是什么关系呢?本文阐述一下作者的理解。
进程的概念
进程是一个具有独立功能的程序关于某个数据集合的一次运行活动。它可以申请和拥有系统资源,是系统进行资源分配和调度的基本单位。进程是一个动态的概念,是一个活动的实体。
“独立功能”表示进程是面向使用者的定义,它关心的是要做什么?比如,在电脑上我要写一篇文章,打开Word。那么计算机就会创建一个Microsoft Word的进程,如果我想同步写两篇文章,就要再打开一个Word,计算机就又创建一个Microsoft Word的进程。
普通的计算机机可以同步做几件事情,比如“上网”,“看电影”,“打游戏”,就是说可以运行很多进程。但是嵌入式计算机通常设计成只做一件事情,比如在汽车领域,整车控制器VCU,发动机喷油点火控制器ECU,变速箱换挡控制器TCU,车身控制器BCM等。这样类比,传统的一个电子控制单元ECU相当于只运行一个进程。未来的XCU就是可以运行多进程的ECU
“资源分配”表示进程操作的对象,它关心的是用什么做?比如整车控制器VCU,
输入资源:加速踏板传感器,刹车踏板传感器等
输出资源:驱动水泵的PWM模块等
通信资源:与TCU,EMS交互数据的CAN通信等。
每个具体的电气资源都会抽象成软件里面的一个具体对象(变量)。
“资源调度”表示进程操作对象的方法,它关心的是怎么用?调度是操作系统的核心,如果没有调度,就算给ECU通电,执行器也不能动作,就不能实现控制功能。
调度的过程是多样的,怎样调度才能最有效的利用资源是软件设计师要考虑的问题。在所有资源中,“CPU”资源是最核心的资源。传感器不够了,可以扩展电路增加一个。但是在单CPU系统中,特别的又只有一个Core,不可能简单的增加一个CPU,这无异于重新设计一个ECU系统。而在原来的CPU上增加一个Core,不是ECU开发商能做的事情。围绕如何有效的利用“CPU资源”,引入了线程。
线程的概念
线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
“运算调度”,表示线程是面向运算器的,即CPU的。在这个层面上,它只关心CPU一个资源,其它的资源不考虑。
“最小单位”,表示一旦被定义为线程,就不应该再向下分子线程了,如果可以分那么在设计程序时应该先分。比如,某个Thread_10ms(),分析发现当中的某些逻辑执行周期应该是2ms,那么就应该把它拆分成Thread_10ms()和Thread_2ms()
“单一顺序流”,表示一个线程一旦启动,它就应该按顺序从头执行完。如果中间被暂停应该记录暂停点,等恢复后从暂停点继续执行。如果恢复后没有从暂停点继续执行,应该为错误。
“不同的任务”,表示一个任务只能交给一个线程执行。否则的话,会导致非预期的结果。比如,有一个任务Task_Printf(“Hello World”),当把它单独挂在10ms进程里,那么屏幕上每隔10ms输出一个“Hello World”;当把它单独挂在2ms进程里,那么屏幕上每隔2ms输出一个“Hello World”。但是在一个可抢占式操作系统里,如果把它们都挂在2个线程里,2ms任务可能会抢占10ms任务。屏幕上可能会输出“Hello Wo Hello World rld”等奇怪的字符串。
任务的概念
笔者翻了很多资料和文章,发现对任务的定义可谓五花八门,例如:
百度的定义:
在多道程序或多进程环境中,要由计算机来完成的基本工作元,它是由控制程序处理的一 个或多个指令序列。
OSEK OS 2.2.3的定义:
复杂的控制软件可以方便地细分为根据其实时性要求执行的部件。这些部件可以通过任务来实现。任务提供了执行功能的框架。操作系统提供任务的并发和异步执行。调度程序组织任务执行的顺序。
μCOS-III的定义:
任务(也称为线程)是一个简单的程序,认为它本身具有中央处理器(CPU)。在单个CPU上,任何给定时间只能执行一个任务。
任务看起来就像任何其他C函数一样,除了一些小的区别。任务有两种类型:完成运行(清单5-1)和无限循环(清单5-2)。在大多数嵌入式系统中,任务通常采取无限循环的形式。同样,不允许任何任务像其他C函数一样返回。鉴于任务是常规C函数,它可以声明局部变量。
TASKING-OS的定义:
任务是具有特定目的的半独立程序段。大多数现代的实时应用程序需要多个任务。任务提供了执行功能的框架。RTOS提供任务的并发和异步执行。调度程序组织任务执行的顺序,包括一种在没有其他系统或应用程序功能处于活动状态时处于活动状态的机制:空闲机制。
任务具有静态优先级,是否可以被抢占,可以或不能进入等待状态,是否是或不是优先级的唯一所有者,依此类推。
SylixOS的定义:
总结下来,在通用计算机操作系统里,只强调进程和线程的概念。而在嵌入式操作系统里,任务就是线程的意思。怎么会这样呢?这是因为一个嵌入式系统设计为只实现一个具体功能的是专用计算机系统,在通用计算机系统只相当于一个进程。而且,通用计算机的一个进程可衍生出几个独立进程,好比你可以打开两个Word文档交互编辑。但是,一个汽车ECU不可能用软件复制的方法控制两台发动机。所以,在一般的嵌入式系统里说进程没有意义(智能手机等多用途设备除外)。从事嵌入式开发的很多都不是计算机专业科班出身的,大多数是电子技术专业毕业,因为硬件开发需要才转入研究嵌入式计算机系统,而线程是计算机术语,没有进程的衬托,一般人不好理解。而任务本身就面向人的词语,所以在大多数嵌入式RTOS里都只讲任务(Task)
然而,笔者觉得还是有必要从计算机术语的角度对这些概念加以清晰的理解。理由有两点:
嵌入式系统的功能逐渐强大,越来越接近通用计算机功能,比如智能手机。在汽车电子领域,XCU是发展的方向,一个XCU肯定是多进程的,光定义任务不够,还要定义它属于发动机,或者变速箱。
任务和线程还是不一样的。比如下面这两句话。
老板给员工说:“你到我办公室来一下”
老板给员工说:“你5点钟到我办公室来一下”
定义“到办公室来”是任务。第一句话没有调度的概念,就是没有线程,什么时候“到办公室来”没有讲(这里不附加默认是现在的意义),那么员工在任何时候都可以去办公室,所以这个任务的执行是不确定的。第二句话,增加了调度时刻“5点钟”,那么这件事情就清晰了。从而,我们可以严格定义进程、线程、任务的关系。
OSEK OS的Application modes:
笔者不打算推翻嵌入RTOS的概念,当然也没有这个必要。在面对计算机时,软件工程师一般都清楚他要做什么,虽然表达上有差异,但不影响对内涵的理解。就像有人喜欢叫“猫”,有人喜欢叫“咪”,都是同一个事情。注意到,在OSEK OS里有Application modes的概念
应用程序模式旨在允许OSEK操作系统在不同的操作模式下运行。许多ECU可能会执行完全独立的应用程序,例如工厂测试,Flash编程或正常运行。应用模式是一种根据这些不同条件构造在ECU中运行的软件的方法,并且是开发完全独立的系统的简洁机制。通常,每种应用程序模式都使用其自己的所有任务,ISR,警报和计时条件的子集,尽管在不同模式下运行任务或ISR不受限制。如果再次需要相同的功能,建议在不同模式之间共享任务/ ISR /警报。
这看起来有点儿像“进程”的概念,前面我们说一个执行特定功能的ECU只有一个进程,但这个只是主进程。一个只有主进程的ECU功能上还是受限制的。比如,ECU在出厂前要测试功能,执行测试的程序肯定与正常工作的程序不一样。旧的程序需要被更新到新的程序,此时需要切换到Boot程序里运行。这实际上就是不同的进程。只是,嵌入式软件里的进程和通用计算机里的进程还不一样。
通用计算机里的进程执行到一半可以切换到另一个进程,比如打字到一半不关闭Word,而切换到看电影。在汽车里面,发动机控制器程序运行到一半暂停,跑到Boot模式,过一会儿再切回发动机控制器程序继续运行?这个在技术上也可以做到,但是肯定不会这样干。有几个理由:
带来安全问题
Boot和App程序要分配独立RAM空间保存各自状态,浪费资源
没有必要,从头开始运行App程序到执行到某个断点也就几十到几百毫秒,保护现场的进程切换节省不了多少时间。
达不到控制目的,汽车软件的一个程序只要运行中停止了,无论是主动的行为还是被动的异常,都会导致当前功能的丧失。程序必须要重新运行才能重启功能。
第4条是最主要的功能,所以汽车软件的进程就三个状态。这样就不需要进程控制块,不需要进程栈。必须要先结束一个进程才能切换到另一个进程。
AutoSar OS的OsApplication
在AutoSarOS标准里新增加了OsApplication的概念,乍一看和OSEK OS的Application modes一样, AUTOSAR OS必须能够支持构成内聚功能单元的一系列操作系统对象(任务,ISR,警报,计划表,计数器)。该对象集合称为OS应用程序。但本质上是不一样的。
AutoSarOS引入OS-Application的目的是为了防止程序的错误传播,引入Trusted OS-A和Non-trusted OS-A属于功能安全的要求。Non-trusted OS-A可以访问Trusted OS-A,反之不可。这类似于面向对象编程的“public”和“private”属性。Private可访问public对象,反之不可。
一个OS Application mode下面可以有很多个OS-Application, OS-Application不是运行实体。它只是定义了资源的隶属关系,当某个调度表/任务访问某个资源的时候,要首先判定我没有这个权限?这个权限来自一张静态定义的OS Application表。
与OS Application类似的是,汽车诊断规范里定义了不同的会话模式能访问的诊断服务的权限。例如,默认会话下不能调用$27服务。但会话模式既不是一个进程,也不是一个OS Application,这个纯粹是软件设计逻辑,与用什么操作系统没关系。