对很多嵌入式系统来说,一个设计良好的实时操作系统(RTOS)可以让开发工程师掌握系统执行任何任务或响应任何关键事件的时间,满足系统实时性要求。为了理解RTOS如何通过系统调度策略实现实时性要求,本文介绍了抢占式调度、可抢占的内核、优先级继承和中断处理等概念。
在设计工业控制系统或医疗设备时,大部分工程师和系统设计工程师会认为采用RTOS是必需的。然而,网际路由器、车载娱乐系统和多媒体设备等普通应用还需要采用RTOS吗?像Linux或Windows这样的通用操作系统是否就能胜 任呢?通常,这些产品需要采用RTOS,但是这个问题常常直到设计阶段的后期才能意识到。
RTOS对于很多嵌入式系统来说不但是有益的,而且也是必要的,认识到这一点很重要。例如,一个播放如MPEG格式电影的设备,如果依靠软件来实现其整个内容传输,可能会出现用户难以接受的高丢帧率。然而,通过使用RTOS,系统设计工程师能够准确地控制软件过程的执行顺序,从而保证按照给定的媒体速率进行播放。上述大部分情况适用于用户希望对输入做出立即响应的系统。通过RTOS,开发人员能够保证由用户的操作总能得到及时的响应,除非一个更重要的操作(如一项有助于保障用户安全的操作)必须首先执行。
总之,一个好的RTOS支持开发人员控制系统执行任何任务或对任何重要事件做出反应的时间,并且能够以一种可以预测并且完全一致的形式满足任务执行的终期限要求。但是,如果RTOS崩溃,这些终期限就不能被满足。因此,RTOS必须提供高度的可靠性。特别是它必须提供在不需要重启的情况下,从软件故障中快速并智能恢复的机制。
抢占式调度
在像Linux这样的通用操作系统中,在对线程和进程的CPU占用上采用了“公平”调度策略。这样的策略能够提供良好的整体表现,但是不能保证高优先级、对时间要求严格的线程将优先于低优先级的线程执行。事实上,操作系统有时甚至会中断高优先级的线程来为低优先级线程提供CPU时间。其结果可能造成对时间要求严格的线程很容易地错过它们的终期限,甚至在一个高速的高端处理器上运行时也会出现这种情况。
而在RTOS中,线程按照其优先级顺序执行。如果一个高优先级的线程准备运行时,它将在一个短的、有间间隔内从任何可能正在运行的低优先级进程接管CPU。另外,高优先级的线程能够不被中断地运行,直到它已经完成了需要做的事情-当然是在不被更高优先级进程抢占的前提下。这种方法就是抢占式调度,保证了高优先级线程始终满足其终期限,而不管有多少其它线程正在竞争CPU时间。
通过合理地控制线程优先级,开发者能显著地提高很多对用户非常重要的应用响应速度。然而,控制优先级可能是一把双刃剑,当使用不当时它可能会潜在地导致低优先级的进程不能得到CPU时间。保证高优先级的进程和线程的同时确保不会使其它进程处于“饥饿”状态的关键是要对它们的执行进行限制,通过对执行进行调整或在响应加载的过程中进行控制,开发人员能够限制这些活动消耗的CPU时间比例,并支持低优先级进程获得对CPU的共享。
优先级控制能够使很多应用受益,包括像前面提到的媒体播放器(MP3、WAV、MPEG2等格式)。媒体播放器需要实现正常播放所要求的速率(例如44kHz的音频、30fps的视频)。在这种限制之下,一个读线程和一个显示线程可以被设计成依靠一个可编程的定时器来唤醒,缓冲或显示一帧后进入睡眠状态,直到下一个定时触发。这提供了一种调整机制,支持高于正常用户活动而又低于关键系统功能的优先级设置。换句话说,如果没有更重要的任务准备运行,媒体播放将始终以给定的媒体速率执行。
坏情形
抢占式调度仅在高优先级的线程在一个短的、有间段内抢占低优先级线程的情况下有效。否则,系统将不可能预测要花费多长时间来执行一个给定的操作。因此,任何销售进程模式的RTOS的供应商都必须提供针对下面两种时间间隔提供坏情形:线程切换时间,即当两个线程处于同一进程的情况下,从执行一个线程的一条指令到执行下一个被调度线程的条指令所经过的时间;前后关系切换(context switch)时间,其定义同上,但仅针对两个线程处于不同进程的情况。
可以将线程看作是的“执行单元”,而将进程看作是一个或多个线程的“容器”,进程定义了线程将要在其中执行的地址空间。显然,坏情形的前后关系切换时间将比坏情形的线程切换时间要慢,尽管在一个好的RTOS设计中差别可能是微不足道的。
将所有的线程放在几个大的进程中将是错误的,因为线程提供的切换速度更快。虽然线程能实现并行处理优势因而适合于某些设计,但将一个应用分成多个内存保护的进程使得代码更容易调试,提供了更好的错误隔离和恢复能力,并允许系统进行新功能的动态升级。
可抢占的内核
在大部分通用操作系统中,操作系统的内核是不可抢占的。其结果是,一个高优先级的进程不可能抢占一个内核调用,而是必须等待整个调用完成,即使这个调用是由系统中的低优先级进程发起的。另外,当经常在内核调用中执行的驱动程序或其它系统服务代表一个客户线程执行的时候,所有的优先级信息常常会丢失,这导致了不可预测的延迟并阻止了关键活动的准时完成。
而在RTOS中,内核操作是可抢占的。尽管仍然会存在一些时间窗口,在这些时间窗口中可能没有抢占,但是这些时间间隔应该是相当短暂的,通常在几百纳秒。另外,必须有一个关于抢占被推迟或中断被禁止的时间上限,这样开发者可以确定坏情形下的等待时间。
为了实现这个目标,操作系统内核必须尽可能简洁,只有具有较短执行路径的服务才被包含在内核中,任何需要大量工作(如进程加载)的操作必须被安排到外部进程或线程。这种方法有助于通过内核确保长的不可抢占代码路径具有一个时间上限。
优先级继承
然而,为一个进程设定一个高优先级并不总能保证该进程能够抢占低优先级的进程。有时候,系统会出现一种称为优先级倒置(priority inversion)的状态,在这种状态下,低优先级的进程将在“无意中”阻止较高优先级进程占用CPU。优先级倒置可能会表现为几种形式,为了防止发生这种情况,RTOS必须提供一种称为优先级继承的功能。
假定系统有三个进程:A(低优先级),B(中等优先级),Z(高优先级)。这里Z是一个为A和B提供服务的“服务器”进程。
现在假定A已经请求Z来执行一个计算,而在这期间,突然B需要Z的服务。因为B拥有比A更高的优先级,一般会认为Z将立即挂起A的请求并将转向为B服务。但是实际情况并非如此,因为Z比B具有更高的优先级。其结果是,B不能阻止Z完成它当前的工作,即对A做出响应。
从效果上看,低优先级的进程A占用了更高优先级进程B的CPU时间,这是引入优先级继承的原因。通过使用RTOS提供的优先级继承机制,系统可以在A发出请求的情况下,让Z继承A的低优先级。通过这种方式,B能够在任何时候抢占A的请求。
如果一个应用程序分布于几个通过网络连接的处理器,那么RTOS也应该支持分布式优先级继承,这样可以按照优先级的顺序处理来自多个处理器的请求。如果没有优先级继承,一个多处理器系统可能会落入无限的优先级倒置和死锁中。
中断处理
为了获得对外部事件的及时响应,化硬件中断发生到执行该中断的条代码的时间很重要。这个时间间隔称为中断延迟,为了保证中断延迟尽可能小,一个好的RTOS应该在几乎所有时间内都支持产生中断。正如在关于内核抢占部分提到的那样,一些重要的代码段的确需要暂时屏蔽中断。这种的屏蔽时间通常被定义为的中断延迟。
在某些情况下,硬件中断处理器必须调度并运行一个更高优先级的线程(例如在一个驱动程序中)。在这样的情况下,中断处理器将返回并指示一个事件将被处理。这样的处理将引入了第二种形式的延迟-调度延迟,这个延时必须在设计中加以考虑。调度延迟是介于用户的中断处理器的一条指令和驱动程序线程条指令的执行之间的时间。
在一个嵌入式系统中可能会同时出现多个硬件中断。例如,在一个病人监护系统中,当一个传感器记录了病人心跳的变化并且网卡接收到网络传来的数据的同时,护士按了触摸屏。很明显,一些中断(如心率的变化)应该立即得到处理,而其他的则可以延缓。通过提供对嵌套中断的支持,RTOS支持嵌入式系统优先处理更高优先级的中断。
如何提高可靠性
我们已经明白怎样使RTOS具有可以预测性,但是如何实现其可靠性呢?答案在很大程度上取决于RTOS的架构。
例如在实时执行模式架构中,大部分或所有软件组件都在一个单一的内存地址空间中运行,包括操作系统内核、网络协议栈、设备驱动程序、应用程序等。虽然很有效率,但这种架构有两个明显的缺陷:1. 在任何组件中的一个指针错误,不论这个错误多么细微,都可能破坏操作系统内核或任何其它组件,导致不可预测的行为和整个系统的崩溃;2. 很难动态修复或替换任何有故障的组件。在大多数情况下,出现这些问题时系统复位是的选择。
一些RTOS,也像Linux一样,试图通过使用单内核架构来解决这个问题。在这种架构中,用户的应用程序在隔离的、受保护内存地址空间中运行。如果一个应用程序试图访问其地址空间之外的数据,内存管理单元(MMU)将通知操作系统,操作系统可能会采取保护措施,例如终止出错进程。然而,这样的操作系统需要将大多数或所有驱动程序、文件系统和其它系统服务绑定到内核中。因此,任何组件中的一个错误都可能带来灾难性的内核故障。
第三种方法是采用微内核(mricokernel)架构来提供更的故障隔离,像QNX Neutrino这样的操作系统都基于微内核架构。微内核有两个明确的特征:
1. 在操作系统内核中只实现了一个包含了基本OS服务的小内核(如信号量、定时器、任务调度等)。包括驱动程序、文件系统、协议栈和用户应用程序在内的所有其它的组件在内核外部分离的、保护内存的进程中运行。有问题的系统服务不再作为孤立的故障点,而是在它破坏其它服务或操作系统内核之前被终止并重启。
2. 所有的组件能够通过消息传递进行通信,一个定义良好的通信机制保障了程序在保持彼此安全隔离的前提下进行数据交换。适当实现的消息传递也可以作为一个虚拟的“软件总线”,允许几乎任何的软件组件,甚至是一个设备驱动程序被动态地加入或替换,对于必须提供连续服务的系统而言这是一项关键要求。
和传统的操作系统架构相比,微内核支持嵌入式设备赢得明显更快的平均修复时间(MTTR)。例如,如果一个设备驱动程序失败将可能出现以下情况:操作系统可以终止该驱动程序,回收其正在使用的资源,并对其进行重新启动,这个过程通常这只需要几个毫秒时间。
尽管和传统的操作系统相比,基于消息传递的微内核RTOS通常提供了更好的容错性和动态升级能力,也有一些观点认为消息传递增加了开销。在实际应用中,如果实现正确,消息传递的性能可以接近底层硬件的内存带宽。例如,一个微内核RTOS可以采用多段式(multipart)消息和线程到线程的消息数据直接拷贝等各种技术,来确保系统性能可以达到传统的进程间通信(IPC)方法的水平。由一些组织如Dedicated Systems(网址:www.omimo.be)等进行的独立测试证实,和传统的RTOS相比,微内核RTOS在一系列的实时指标方面表现良好,在很多情况下甚至有更好的表现。
策略决策
RTOS有助于使一个复杂的应用程序具有可预测性和可靠性。当然,选择一个合适的RTOS本身就是一项复杂的任务,而RTOS的底层架构是选择的重要依据,此外还有一些其它因素,包括:
1. 调度算法的灵活选择。RTOS应该支持调度算法的选择(先入先出(FIFO)、轮询(round robin)、零星调度等)并支持以线程为单位设定这些算法。这样,工程师就可以不必将一个算法用到系统中的所有线程。
2. 图形用户界面(GUI)。RTOS使用的是原始的图形库还是能支持多层界面、多路显示、3D渲染以及其它的图形功能的真正的窗口系统?能很容易定制GUI的外观吗?GUI支持同时显示和输入多种语言(汉语、韩语、日语、英语、俄语等)吗?
3. 远程诊断工具。因为对很多嵌入式系统而言,中断系统运行进行检测和维护是无法接受的。RTOS供应商应该提供诊断工具,这些工具能够在不中断系统服务的前提下分析系统的行为。要寻找能提供代码覆盖、应用测评、跟踪分析和内存分析工具的供应商。
4. 开发平台。RTOS提供商提供的开发环境是基于像Eclipse那样的开放平台,允许工程师嵌入所喜爱的第三方工具来进行建模、版本控制吗?还是开发环境基于技术?
5. 互联网功能。RTOS支持预集成的IPv4、IPv6、IPsec、SCTP和具有NAT功能的IP过滤等协议栈套件吗?它支持嵌入式网络浏览器吗?浏览器应该具有可扩展的封装模式,并能够在很小的屏幕上绘制网页。它也应该支持像HTML 4.01、XHTML 1.1、SSL 3.0和 WML 1.3这样的标准。
6. 标准API。RTOS将你限定到专有的API之中了吗?还是它对于像POSIX这样的标准API提供了完全的支持,这使得将代码移植到其它操作系统,或者从其它操作系统移植代码变得更容易?另外,所用的RTOS提供完全一致性的API还是仅仅支持被定义接口的一个子集?例如,POSIX.1的版本包含了大约1,300个接口。
7. 多处理技术。RTOS能支持对称多处理和分布式多处理技术来提高应用性能和容量吗?如果这样,是必须重新设计你的应用程序呢,还是RTOS能够将应用程序透明的分配到多个处理器上去呢?
8. 源代码工具包。RTOS供应商提供了能使RTOS满足设计需求的具有详细文档的定制工具包吗?供应商提供了方便开发驱动定制硬件的驱动程序开发工具包吗?
9. 对于很多公司而言,选择一款RTOS是一项战略性决策。RTOS供应商在对上述问题提供了清楚的回答后,你将选择出一个在现在和将来都适合你的RTOS。
免责声明: 凡注明来源本网的所有作品,均为本网合法拥有版权或有权使用的作品,欢迎转载,注明出处。非本网作品均来自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。