RTOS 在嵌入式开发中占有重要地位,那么,到底什么时候才需要用到 RTOS?
究竟何时需要实时操作系统?
大多数嵌入式项目是否仍需要实时操作系统?考虑到当今高性能处理器的速度以及适用于 Linux,Windows 和其他通用操作系统(GPOS)的实时补丁的可用性,这是一个很好的问题。
答案在于嵌入式设备的本质。这些设备通常以数千,甚至数百万套这种规模下生产,即使每套硬件成本降低1美元,也能为制造商节省一笔小财富。换言之,这些设备无法负担数百万赫兹处理器的成本(更不用说散热了)。
例如,在汽车远程信息处理市场,典型的 32 位处理器的运行频率约为 600 兆赫,远低于台式机和服务器中常见的处理器。在这样的环境中,设计用于从低端硬件中提取极其快速、可预测的响应时间的实时操作系统有巨大的经济优势。
除了节省成本外,实时操作系统提供的服务使许多计算问题更容易解决,特别是当多个活动竞争一个系统的资源时。例如,考虑一个用户期望(或需要)立即响应输入的系统。使用实时操作系统,开发人员可以保证由用户发起的操作将优先于其他系统活动执行,除非必须首先执行更重要的活动(例如,有助于保护用户安全的操作)。
还要考虑一个必须满足服务质量(QoS)要求的系统,例如显示实时视频的设备。如果设备的内容交付的任何部分都依赖于软件,那么它会以用户认为不可接受的速度体验掉帧,设备是不可靠的。然而,通过实时操作系统,开发人员可以精确地控制软件进程的执行顺序,并确保以适当和一致的速率进行回放。
实时操作系统不公平
在嵌入式行业中,对实时“硬”时间的需求仍然很普遍。问题是:实时操作系统有什么是 GPOS 没有的?而且,对于某些 GPOS 来说,现在的实时扩展有多有用?他们能提供一个合理的实时操作系统性能吗?
让我们从任务调度开始。在 GPOS 中,调度程序通常使用“公平”策略将线程和进程分派到 CPU。这样的策略可以实现桌面和服务器应用程序所需的高整体吞吐量,但不能保证高优先级、时间紧迫的线程优先于低优先级的线程执行。
例如,GPOS 可能会降低分配给高优先级线程的优先级,或者为了保证系统中其他线程的公平性而动态调整线程的优先级。因此,高优先级线程可能被低优先级线程抢占。此外大多数 GPOS 具有无界的调度延迟:系统中的线程越多,GPOS 调度一个执行线程所需的时间就越长,这些因素中的任何一个都可能导致高优先级线程错过最后期限,即使是在高速 CPU 上。
此外,高优先级线程可以不间断地运行,直到它完成它需要做的事情,当然,除非它被一个更高优先级的线程抢占。这种方法被称为基于优先级的抢占式调度,允许高优先级线程满足其最后期限,即使许多其他线程正在争夺 CPU 时间。
如过需要学习更多操作系统开发实践技术,可参加牛喀学城的培训课程,本课程由国际顶级设备商资深 RTOS 开发专家打造,系统讲授 Kernel,BSP,IDE 等应用实践技术,并辅助以实际开发板进行案例实践操作。点击海报了解详情。
抢占式内核
在大多数 GPOS 中,os 内核是不可抢占的。因此,高优先级用户线程永远不能抢占内核调用,而是必须等待整个调用完成—即使调用是由系统中优先级最低的进程调用的。此外,当驱动程序或其他系统服务(通常在内核调用中执行)代表客户端线程执行 exe 剪切时,所有优先级信息通常都会丢失。这种行为会导致不可预知的延迟,并阻止关键活动按时完成。
另一方面,在实时操作系统中,内核操作是可抢占的。与在 GPOS 中一样,在时间窗口中可能不会发生抢占,在设计良好的实时操作系统中,这些窗口非常短,通常是数百纳秒的顺序。此外,实时操作系统对抢占延迟和中断禁用的时间设置了一个上限;这个上限允许开发人员确定最坏情况下的延迟。
为了实现一致的可预测性和关键活动的及时完成这一目标,实时操作系统内核必须尽可能简单优雅。实现这种简单性的最佳方法是设计一个内核,该内核只包含具有短执行路径的服务。通过从内核中排除工作密集型操作(例如进程加载)并将其分配给外部进程或线程,实时操作系统设计器可以帮助确保通过内核的最长不可抢占代码路径上存在上限。
在一些 GPOS 中,内核增加了一定程度的抢占性。然而,不可能发生抢占的时间间隔仍然比典型实时操作系统中的时间间隔长得多;任何此类抢占时间间隔的长度将取决于 GPOS 内核中任何模块(例如,网络)的最长关键部分。此外,一个可抢占的 GPOS 内核不会处理其他可能造成无限延迟的条件,例如,当客户端调用驱动程序或其他系统服务时发生的优先级信息丢失。
避免优先级反转
在 GPOS 中,甚至在实时操作系统中,低优先级线程可能无意中阻止高优先级线程访问 cpu,这种情况称为优先级反转。当发生无限优先级反转时,可能会错过关键的最后期限,从而导致从异常系统行为到彻底失败的结果。不幸的是,在系统设计过程中,优先级反转常常被忽略。优先级反转的例子很多,其中包括 1997 年 7 月火星探险者项目。
一般来说,当两个不同优先级的任务共享一个资源,而高优先级的任务无法从低优先级的任务获得资源时,就会发生优先级反转。为了防止这种情况超过有限的时间间隔,实时操作系统可以提供 GPOS 中不可用的机制选择,包括优先级继承和优先级上限模拟。我们不可能公正地对待这两种机制,所以让我们关注一个优先级继承的例子。
首先,我们必须考虑任务同步如何导致阻塞,以及阻塞如何反过来导致优先级反转。假设两个任务正在运行,任务 1 和任务 2,并且任务 1 具有更高的优先级。如果任务 1 已准备好执行,但必须等待任务 2 完成活动,则会阻塞。此阻塞可能是由于同步造成的;例如,任务 1 和任务 2 共享由锁或信号量控制的资源,而任务 1 正在等待任务 2 解锁该资源。或者,可能是因为任务 1 正在请求任务 2 当前使用的服务。
阻塞允许任务 2 运行,直到发生任务 1 正在等待的条件(例如,任务 2 解锁两个任务共享的资源)。此时,任务 1 开始执行。任务 1 必须等待的总时间称为阻塞因子。如果任务 1 要满足其任何时间限制,则此阻塞因子不能随任何参数(例如线程数或系统输入)而变化。换句话说,阻塞因子必须是有界的。
现在让我们介绍第三个任务,任务 3,它的优先级高于任务 2,但低于任务 1(参见图 1)。如果任务 3 在任务 2 执行时准备好运行,则它将抢占任务 2,并且任务 2 将无法再次运行,直到任务 3 阻塞或完成。当然,这个新任务会增加任务 1 的阻塞因子;也就是说,它会进一步延迟任务 1 的执行。抢占引入的总延迟是一个优先级反转。
图 1 任务 1 正在等待任务 2 完成一个活动,这时任务 3 抢占了任务 2。此新任务进一步延迟任务 1 的执行
实际上,多个任务可以通过这种方式抢占任务 2,从而产生一种称为链阻塞的效果在这种情况下,任务 2 可能会被无限期抢占,从而产生无限的优先级反转,并导致任务 1 无法满足其任何最后期限。
这就是优先级继承的来源。如果我们返回到我们的场景,并使任务 2 在同步期间以任务 1 的优先级运行,那么任务 3 将无法抢占任务 2,从而避免产生优先级反转(参见图 2)。
图 2 任务 2 继承任务 1 的较高优先级,从而防止任务 3 抢占任务 2。任务 3 不再延迟任务 1 的执行。
分区调度器
对于许多系统,保证资源可用性是至关重要的。如果一个关键的子系统被剥夺了,比如说,CPU 周期,那么这个子系统提供的服务对于用户来说就变得不可用了。例如,在拒绝服务(DoS)攻击中,恶意用户可以用需要高优先级进程处理的请求轰炸系统。这个进程可能会使 CPU 超载,使其他进程的 CPU 周期中断,从而使系统对用户不可用。
安全漏洞并不是进程饥饿的唯一原因。在许多情况下,向系统添加软件功能会将系统推向“崩溃的边缘”,并使现有的应用程序占用大量 CPU 时间。及时运行的应用程序或服务不再按预期或要求作出响应。从历史上看,解决这个问题的唯一办法要么是改造硬件,要么是重新编码(或重新设计)软件——两者都是不受欢迎的选择。为了解决这些问题,系统设计人员需要一个分区方案,通过硬件或软件强制执行 CPU 运算,以防止进程或线程独占其他进程或线程所需的 CPU 周期。由于实时操作系统已经提供了对 CPU、内存和其他计算资源的集中访问,所以实时操作系统是执行 CPU 分区运算的最佳选择。
有些实时操作系统提供一个固定的分区调度器。使用此调度器,系统设计人员可以将任务划分为组或分区,并为每个分区分配一定百分比的 CPU 时间。使用这种方法,任何给定分区中的任务消耗的 CPU 时间都不会超过分区静态定义的百分比。例如,假设一个分区分配了 30% 的 CPU。如果该分区中的进程随后成为拒绝服务攻击的目标,那么它消耗的CPU时间将不超过 30%。这个分配的限制允许其他分区保持其可用性;例如,它可以确保用户界面(例如远程终端)保持可访问性。因此,操作员可以访问系统并解决问题,而不必按下复位开关。
然而,这种方法有一个问题。因为调度算法是固定的,所以一个分区永远不能使用分配给其他分区的 CPU 周期,即使这些分区没有使用它们分配的周期。这种方法会浪费 CPU 周期,并阻止系统处理峰值需求。因此,系统设计者必须使用更昂贵的处理器,容忍更慢的系统,或者限制系统能够支持的功能数量。
自适应分区
另一种分区方案称为自适应分区,它通过提供更动态的调度算法来解决静态分区的缺点。与静态分区一样,自适应分区允许系统设计人员为一个进程或一组进程保留 CPU 周期。因此,设计人员可以保证一个子系统或分区上的负载不会影响其他子系统的可用性。但是,与静态方法不同,自适应分区可以动态地将 CPU 周期从不繁忙的分区重新分配给可以从额外处理时间分区预算中受益的分区,只有在 CPU 完全加载时才强制执行。因此,系统可以处理峰值调度应用程序不需要改变它们的调度行为。此外,设计人员可以动态地重新配置分区,以优化系统的性能。参加牛喀学城汽车操作系统技术培训,学习更多实用技术。扫描文末二维码报名。
“双重”内核
包括 Linux、Windows 和各种风格的 unix 在内的 GPOS 通常缺乏迄今为止讨论的实时机制。为了填补这个空白,GPOS 供应商开发了大量的实时扩展和补丁。例如,有一种双内核方法,在这种方法中,GPOS 作为一个任务运行在一个专用的实时内核之上(参见图 4)。因此,这些任务可以在 GPOS 需要执行时抢占它们,并且仅在 GPOS 完成工作时才将 CPU 交给它们。
不幸的是,在实时内核中运行的任务只能有限地使用 GPOS 中的现有系统服务——文件系统、网络等等。事实上,如果某个实时任务向 GPOS 请求任何服务,那么该任务将受到相同的优先处理要求并实现 100% 的利用率,同时享受资源保障的好处。
同样重要的是,自适应分区可以覆盖在现有系统之上,而无需重新设计或修改代码。系统设计人员可以简单地在分区中启动现有的基于 POSIX 的应用程序,而实时操作系统调度器可以确保每个分区都收到分配的预算。在每个分区中,每个任务都根据基于优先级的抢占规则进行调度。
图 3 自适应分区可以防止高优先级任务消耗超过分配的 CPU 百分比,除非系统包含未使用的 CPU 周期。例如,任务 A 和 D 可以在分配给分区 3 的时间内运行,因为任务 E 和 F 不需要剩余的预算 CPU 周期。
阻止 GPOS 进程确定性行为的问题。因此,必须专门为实时内核创建新的驱动程序和系统服务,即使 GPOS 已经有了类似的服务。而且,实时内核中运行的任务无法从大多数 GPOS 为常规,非实时流程提供的受 MMU 保护的强大环境中受益。相反,它们在内核空间中不受保护地运行。因此,包含常见编码错误(例如损坏的 C 指针)的实时任务很容易导致致命的内核错误。这是一个问题,因为大多数需要实时的系统也需要很高的可靠性。更复杂的是,双内核方法的不同实现使用不同的 api。在大多数情况下,为 GPOS 编写的服务不能轻松地移植到实时内核,为一个供应商的实时扩展编写的任务可能不能在另一个供应商的扩展上运行。
图 4 在典型的双内核实现中,GPOS 作为单独的实时内核中优先级最低的任务运行。
这些解决方案指出了使 GPOS 能够支持实时行为的真正困难和巨大范围。这并不是“实时操作系统好,GPOS 坏”的问题。诸如 Linux、Windows 和各种 unix 等 GPOS 都可以很好地作为桌面或服务器操作系统使用。然而,当它们被迫进入非为环境而设计的确定性环境时,如车载远程信息处理单元、医疗器械、实时控制系统和连续媒体应用程序,它们就不能满足要求。
扩展操作系统 特定于应用程序的需求
无论它们在确定性环境中的缺点是什么,使用它们都是有好处的。
这些优点包括对广泛使用的 api 的支持,以及对 Linux 的开放源码模型的支持。使用开放源码,开发人员可以根据特定于应用程序的需求定制操作系统组件,从而节省大量的故障排除时间。实时操作系统供应商不能忽视这些好处。对 POSIX api (Linux 和各种风格的 unix 使用的相同 api)的广泛支持是重要的第一步。提供文档良好的源代码和定制工具包,以满足嵌入式开发人员的特定需求和设计挑战,也是如此。
实时操作系统的架构也起了作用。例如,基于微内核设计的实时操作系统可以使操作系统定制的工作从根本上比其他体系结构更容易实现。在微内核实时操作系统中,只有一小部分基本操作系统服务(例如,信号、计时器、调度)驻留在内核本身中。所有其他组件——驱动程序、文件系统、协议栈、应用程序——作为独立的、受内存保护的进程在内核之外运行(参见图 5)。事实上,作为用户空间程序,这样的扩展变得和标准应用程序一样容易开发,因为它们可以用标准的源代码级工具和技术进行调试。
图 5 在微内核实时操作系统中,系统服务作为标准的用户空间进程运行,从而简化了操作系统自定义的任务。
例如,如果设备驱动程序试图访问其进程容器之外的内存,操作系统可以识别负责的进程,指示错误的位置,并创建一个可以用源代码级调试工具查看的进程转储文件。转储文件可以包含调试器识别导致问题的源代码所需的所有信息,以及诸如数据项的内容和函数调用历史等诊断信息。
这种体系结构还提供了更好的故障隔离和恢复:如果驱动程序、协议栈或其他系统服务出现故障,它可以在不破坏其他服务或操作系统内核的情况下进行故障隔离和恢复。事实上,“软件监督”可以持续监视此类事件,并动态地重新启动违规服务,而无需重新设置整个系统或以任何方式涉及用户。类似地,可以动态地停止、启动或升级驱动程序和其他服务,而无需关闭系统。
这些好处不应该被忽视——对实时性能的最大破坏是计划外的系统重新启动!即使计划重新启动以合并软件升级也会干扰操作,尽管是以一种受控的方式。为了确保最后期限总是能够满足,开发人员必须使用能够持续可用的操作系统,即使在软件故障或服务升级的情况下也是如此。
一个战略决策
实时操作系统有助于使复杂的应用程序既可预测又可靠;事实上,实时操作系统对时间的精确控制增加了 GPOS 无法实现的可靠性。(如果基于 GPOS 的系统由于不正确的计时行为而不能正确工作,那么我们可以合理地说该系统是不可靠的。)然而,选择正确的 rtos 本身可能是一项复杂的任务。实时操作系统的底层架构是一个重要的标准,但其他因素也是如此。其中包括:
• 灵活选择调度算法-实时操作系统是否支持选择调度算法(FIFO,循环调度,零星调度等?)开发人员可以按线程分配算法,还是实时操作系统强迫他为系统中的所有线程分配一种算法?
• 时间分区-实时操作系统是否支持时间分区,以便为进程提供一定百分比的 CPU 周期?这样的保证简化了从多个开发团队或供应商集成子系统的工作。它们还可以确保关键任务仍然可用并满足其最后期限,即使系统受到拒绝服务(DoS)攻击和其他恶意攻击。
• 支持多核处理器——迁移到多核处理器的能力已经成为各种高性能设计的基础。实时操作系统是否支持多处理模型(对称多处理、非对称多处理、绑定多处理)的选择,以帮助开发人员充分利用多核硬件?系统跟踪工具是否支持实时操作系统,以便开发人员诊断和优化多核系统的性能?如果没有能够突出资源争用、过度的线程迁移和多核设计中常见的其他问题的工具,优化多核系统很快就会成为一项繁重、耗时的任务。
• 用于远程诊断的工具-由于许多嵌入式系统无法容忍停机,因此实时操作系统供应商应提供诊断工具,可以分析系统的行为而不会中断系统提供的服务。寻找一个提供用于系统分析,应用程序分析和内存分析的运行时分析工具的供应商。
• 开放式开发平台-实时操作系统供应商是否提供基于开放式平台(如 Eclipse)的开发环境,从而允许开发人员“插入”他们喜欢的第三方工具来进行建模,版本控制等?还是开发环境基于专有技术?
• 图形用户界面-实时操作系统是使用原始图形库,还是支持多种人机界面技术(HTML5、Qt、OpenGL ES等),并提供高级图形功能,如多层界面、多头显示、加速 3D 渲染和真正的窗口系统?gui 的外观和感觉可以很容易地定制吗?guis 能同时显示和输入多种语言(汉语、韩语、日语、英语、俄语等)吗?二维和三维应用程序可以轻松地共享同一屏幕吗?标准 api-实时操作系统是将开发人员锁定到专有 api 中,还是为 posix 和 opengl es等标准 api 提供经认证的支持,从而使代码更易于在其他环境之间进行移植?此外,实时操作系统是否提供了对 api 的全面支持,或者它只支持定义接口的一小部分?
• 标准 api-实时操作系统是将开发人员锁定到专有 api 中,还是为 posix 和 opengl es 等标准 api 提供经认证的支持,从而使代码更易于在其他环境之间进行移植?此外,实时操作系统是否提供了对 api 的全面支持,或者它只支持定义接口的一小部分?
• 针对数字媒体的中间件——对数字媒体的灵活支持正在成为一系列嵌入式系统的设计要求,包括汽车收音机、医疗设备、工业控制系统、媒体服务器,当然还有消费电子产品。一个系统可能需要处理多个媒体源(设备、流等),理解多个数据格式,并支持多种 drm 方案。通过为数字媒体提供设计良好的中间件,实时操作系统供应商可以消除连接到多个媒体源、组织数据和启动适当的数据处理路径所需的大量软件工作此外,一个设计良好的中间件解决方案将有灵活性来支持新的数据源,如下一代 iPod,而不需要修改用户界面或其他软件组件。
对于任何项目团队来说,选择实时操作系统都是一项战略决策。实时操作系统供应商为上述问题提供清晰的答案后,您将可以选择现在和将来最适合的。
声明:本文素材来源网络,版权归原作者所有。如涉及作品版权问题,请与我联系删除。
END
来源:嵌入式专栏
推荐阅读
欢迎大家点赞留言,更多 Arm 技术文章动态请关注极术社区嵌入式客栈专栏欢迎添加极术小姐姐微信(id:aijishu20)加入技术交流群,请备注研究方向。