original in es Ismael Ripoll
es to en Miguel Ángel Sepúlveda
en to zh_CN SEVEN
“一个实时系统首先是一个信息系统,它的正确性不仅仅依赖于算法的逻辑输出, 还依赖于产生这些逻辑输出的及时性。”
仅仅有正确的输出结果是不够的,输出结果还必须在一个特定的时间间隔内到来。 需要注意:在上面的定义中,一个实时系统并不是像人们很自然地想到的那样必须要快。 比方说:一个船只导航系统,由于它的速度很慢,并且人们经常有“充足” 的时间来对它的控制作出决定,所以初看起来可能不像一个实时系统。 但无论如何,根据我们的定义,它就是一个实时系统。
注意我们定义的是一个“实时系统”而不是一个“立即系统”。 一个立即系统通常非常快,并且可以给人很“现实”的印象。 典型地,所有的模拟器和交互式游戏都需要给用户一个连续的时间画面, 并且,在单位时间内能生成的图像越多越好。
下面我们来更详细地考虑一下“瞬时限制”的概念。 假设一个人想通过控制一个引擎的速率来应付不同的负载, 并假设他想使用一个PID(Proportional- Integral-Derivative)控制。 从我们的观点来看,PID控制就是一个函数,它接受一组参数 (在这个例子中是引擎的速率),并且返回一个能应用于引擎的控制信号的值, 根据这个值来对引擎施加相应的电压。PID算法设计背后的理论(顺便提一下它是多方面的) 假设计算时间是可以忽略不计的,也就是说,从读取引擎的速率到我们开始执行这一段时间很短。 正常情况下,系统允许有一段小的延迟。 这种类型的控制的另一个特性就是它必须周期性地执行。 换言之,PID算法必须按照一定的规则执行。 如果连续两次调用PID函数间隔的时间太长, 那么引擎可能会达到一个我们所不期望的速率。总的来讲: PID算法可以被看作一个程序,它必须周期性地执行(Pi); 从它开始执行直到结束所经过的时间绝对不能大于设计PID时指定的最大时间(Di), 并且,根据处理器的速度,PID代码也需要一个特定的时间(Ci) . 。
如果系统是单任务的,那么做一个实时系统不存在任何问题: 处理器或者能在所需要的时间内完成任务,或者不能。 如果处理器不是足够快,那么我们只需要换一个快一些的CPU。
当系统是由多个任务组成的,并且需要为它们分配一个(或多个)处理器的处理能力时, “实时”问题就出现了。这阻碍了我们使用一个经典的分时系统,比方说Linux。 当然,绝没有必要去提那些诸如“不要在Windows上编写需要实时性的程序”之类的事了。 一个好一点的建议是:不要在那种平台上写任何类型的程序。
并不是所有的实时系统都是相同的: 控制一个汽车的ABS刹车系统或飞行器引擎的燃料注射系统和控制一个MPEG文件的解压及视觉效果是不同的。 在第一种情况下,执行时间的一个小的延迟就有可能危及驾驶员的生命安全或者会导致大量的物质损失。 而第二种情况只会引起系统质量的退化(图像可能会停住并可能丢失一些帧)。 第一种类型的系统被称作硬实时系统,第二种为软实时系统。 在此我们将集中讨论硬实时系统。
设计一个硬实时系统要经过几个阶段:首先, 要执行的任务和瞬时限制必须经过鉴定能满足我们的条件; 第二,编写代码,每一个实时任务都要经过测量和调度测试, 以保证在系统运行过程中每个任务都不能超过它所允许的时间最大值。 调度测试由应用于一系列测试的整个任务集组成, 如果能通过第二阶段的测试,就有可能保证没有任务可能会运行超过最大的期限。 如果测试不能通过的话,那么设计就必须重新从头开始: 选择一个快一点的CPU,或者使用其它的算法来实现这些任务。
总结起来,任务有三个时间标识:Pi,Di和Ci。系统的目标是, 保证所有的任务在所有的执行过程中都不超过系统允许的时间最大值。 为了保证运行时间,系统必须是可预测的。 说一个系统是一个实时系统和说一个系统是可预测的实际上是一样的。
系统响应语义的正确性是程序员的责任,而瞬时的正确性依赖于操作系统(OS)。
操作系统必须能支持和组织所有任务的执行,处理中断也是它的职责。 操作系统必须提供:
与普通的操作系统不同,实时操作系统的目标是最大程度地减少复杂性。 我们不需要一个能做很多事情的系统,最重要的是它能在规定的时间内可预测地执行我们的任务。
在一个实时系统上,一个正常情况下需要10个单位时间的任务, 由于上下文环境的改变,在最坏的情况下消耗12的单位时间是可取的。 而在其它普通的操作系统上,一个平均情况下需要3个单位时间的程序经常会执行20个单位时间。
如果发现一个实时系统比普通的操作系统“慢”,我们不必感到奇怪。 有时候,为了获得可预测的行为,甚至需要禁止使用Cache, 这会带来一些性能上的丢失。对一个实时系统来说, 处理器Cache所提供的管道线单元和预言跳转算法是最大的敌人。
POSIX是可移植操作系统接口(Portable Operating System Interface)的首字母缩写(可是为什么OS这个缩写后面没有一个X呢?)。 这一标准意在期望获得源代码级的软件可移植性。 换句话说,为一个POSIX兼容的操作系统编写的程序, 应该可以在任何其它的POSIX操作系统(即使是来自另一个厂商)上编译执行。 POSIX标准定义了操作系统应该为应用程序提供的接口:系统调用集。 POSIX是由IEEE (Institute of Electrical and Electronic Engineering) 开发的,并由ANSI (American National Standards Institute)和 ISO (International Standards Organisation)标准化。 很显然POSIX是基于UNIX的,大多数的操作系统(包括Windows NT)都倾向于开发它们的变体版本与POSIX兼容。
POSIX的定义被分为几个工作组:包括计算机厂商、软件公司、 政府部门和计算机设计师。每一个工作组关于操作系统的某一方面。 例如:POSIX.4组是关于实时方面的内容。
POSIX.4的扩展(1993年更名为1003.1b)允许一个操作系统在实时情况下使用。 很明显,这些扩展大部分都是关于时间管理和进程优先级, 也有一些系统调用来协助进行进程间通信。
POSIX扩展被设计用来增强操作系统对资源的管理控制能力。
Linux2.0为实时性实现了许多符合POSIX扩展的系统调用, 但Linux这一方面的内容我们将在以后进行讨论。 它的2.2版本基本上100%与POSIX 1003.1b兼容。
RT-Linux是在新墨西哥矿业及科技学院计算机系由 Victor Yodaiken和Michael Barabanov开发出来的。 它是Michael提交的完成计算机科学硕士论文的一部分。 新最可用的版本是0.6。现在只用在INTEL体系结构的计算机上。
RT-Linux是用一种完全不同的方式解决这一问题的。 有别于修改Linux系统的内核以使其具有可预测性,它直接在处理器(i386) 上建立了一个具有一个调度器的小的核心(与Linux kernel相独立), Linux内核在这一核心上运行,并与其它实时任务分享处理器。 那么Linux与其它任务分享CPU,更精确地说,Linux是后台的任务, 只有没有其它实时任务执行的时候它才会运行。
我猜想读者现在可能困惑了,可能是因为有人想操作系统是一个整体, 怎么可以修改它?
更令人惊奇的是:事实上,如果作为一个模块编译的话, 你可以动态地装入和移除调度器。
与其它操作系统类似,作为同步方式或者为了实现临界区, Linux内核代码通常会关闭中断。如果在Linux关中断期间来了一个时钟中断, 它就会阻塞,这将导致丢失瞬时精确度。RT-Linux使用了一个非常优雅的解决方案: 所有对CLI、STI和IRET(修改中断状态的汇编调用)的调用都用 S_CLI、S_STI和S_IRET来代替和模拟,这样,Linux就永远不能禁止中断调用。
RT-Linux缺省的调度策略是抢占式、固定优先级的调度, 并对Linux任务赋予了较低的优先级。 如果实时任务消耗了所有的CPU时间,那么Linux任务将不能获得任何CPU时间, 看起来就像是停止了一样。
使用RT-Linux我们不仅有了一个实时系统,还有了一个经典的操作系统。 在采样和控制一个物理系统的同时我们还可以上网冲浪。
这一发行版的文件可以在下面获得: http://luz.cs.nt.edu/~rtlinux.
为了把一个Linux系统改成RT-Linux, 我们必须把RT-Linux提供的内核补丁应用到内核源代码上并重新编译内核。 下面是编译的方法。我们假设rtlinux-0.6-2.0.33.tgz在目录/usr/src下, 并且它已被解压缩到/usr/src/rtlinux-0.6。 我们还假定所有的内核选项都已经配置(make config)好了。接下来
# cd /usr/src/linux # patch -p1 <../rtlinux-0.6-2.0.33/kernel_path # make dep; make clean; make zlilo; make modules; make modules_install # reboot
新内核跟一个普通的内核看起来没什么差别, 但它已经准备好转换为一个实时系统了。 在/usr/src/rtlinu-0.6-2.0.33/testing下有各种各样的演示程序。
除了发行版在testing目录中的例子,你还可以下载Oleg Subbotin为我们准备的另一个示例程序,它允许我们创建任务的执行记录。 这一示例的一个文件是一个修改了的调度器,它不仅能执行任务调度, 还能够发送关于任务决策的信息。这一信息被收集并存储于一个文件中, 以后可以图形化的显示。结果我们就可以看出各种任务是以什么顺序执行的, 具有高优先权的任务是如何抢占低优先级的任务的。Linux任务没有表现出来。
每一个任务都表现在一个水平轴上。长方形表示每一个任务占用CPU的时间 (因为我们使用一个单处理器的系统,所以在同一时刻只能有一个实例在运行), 在这个例子里,每一项任务的最大允许执行时间与他们的周期相同, 这一周期用一个时间间隔标记(用代表)。在这一间隔内任务必须执行完毕。 上面部分的任务具有较高的优先级,并且能从其它任务(如600位置)抢占处理器,
现在已经有了一个多处理器的RT-Linux版本。为了尽可能地保持系统的可预见性, RT-Linux所能提供的服务被故意地限制的很少, 因为没有必要包含那些对实时性要求不严格的功能。
几周以前开始了一个RT-Linux手册-教程的编写工作。(本文文写于1998年:译者注)
在RT-Linux出现以前,大多数需要实时系统的工程师被迫使用MS-DOS并且建立所有需要的驱动, 或者是以非常惊人的价钱购买一个真正的实时操作系统。 现在开发者们有了一个全功能的操作系统, 他们可以在与将要运行于其上的相同的系统上开发实时的程序。 实际上,我们在上网冲浪的同时再运行几个实时程序也没有问题。
我们这一系列以后的文章中会研究几个实时应用程序的例子, 以及如何编写我们自己的实时程序。