RTOS简介
1.6 处理复杂的多重工作
现在我们来看看更为复杂的系统,下图是许多中小型应用的典型代表。它的主要功能是控制发动机喷气管的温度。使用热电偶测量温度,将产生的模拟信号数字化,在计算机内部计算误差信号,然后向燃油阀输出校正信号。不过,该装置还需要完成几项辅助工作。首先,飞行员需要通过键盘/显示装置获取所有系统信息。其次,飞行记录器必须能够通过串行数据链获得相同的信息。根据系统信息,我们现在着手开发软件系统。基于功能设计方法的模型如图。
开发过程的下一阶段是将每个子系统作为一个单独的代码单元来实现。这一点很容易。但要让执行引擎正确运行这些单元则是另一
回事;考虑到上述操作要求,这种解决方案不太可能奏效。
问题源于函数固有的 “异步并行性”(独立并发)。这意味着我们有许多不同的任务,在现实世界中,这些任务可能有
- 以固定时间间隔提供服务–周期性功能
- 在随机(而非预设)时间提供服务–异步或非周期函数。
- 同时处理。
- 对时序的要求截然不同。
看一看这个系统的定时要求,就会明白为什么先前的方法会失败。
定时信息
- 控制回路: 周期性,采样率为10赫兹,即周期为100毫秒。
- 控制回路: 预计计算时间为5毫秒。
- 串行通信: 本设计使用4字节缓冲接收器-发送器 (RT),数据传输速率为1Mbit/秒,信息长度为8字节。请注意,这意味着当信息流到达时,缓冲区将在 32 微秒内填满。
- 显示: 计算机对键盘操作必须有可接受的响应时间。250毫秒应该足够了。
如果 RT设备的缓冲区超限,现有数据将被破坏。为防止这种情况发生,必须在超限发生前读取当前数据。如果使用轮询来检测 RT 数据,则必须以非常高的速率进行(一阶近似值为每 32 微秒)。
结果就是,不可能以简单的方式对优雅的软件设计模型进行编码。用一句众所周知的话来说,就是我们的实现技术 “脱胎换骨”了。那么,怎样才能摆脱困境呢?答案就是改变我们的执行引擎;使用处理器中断机制来驱动软件。
1.7 使用中断作为执行引擎–简单的准并发程序
计时器超时、按下开关、外围设备需要关注。这些都是计算机系统中典型的真实事件。但软件究竟是如何知道现实世界中发生了什么事情的呢?事实上,检测此类事件的方法只有两种:寻找事件(轮询)或直接向处理器发送信号(硬件中断)。
在前面的工作中,我们在单个顺序程序单元内使用了轮询。现在我们来看看硬件中断,这是一种以电子方式向处理器发出的信号。当中断产生时,它会调用预定的响应(由程序员定义)来执行一些指定的代码。因此,可以将中断视为特定软件的代码执行引擎。将这一技术应用于发动机温度控制系统,可以得到下图的运行时模型(请注意,这只是基于我们的经验和偏见;设计方案并非独一无二)。
这里的中断由之字形箭头线表示,代表中断信号的来源。例如,中断1由定时器芯片的输出逻辑信号产生。激活后,温度控制环路开始执行,运行完成后停止,等待下一个中断。中断2也是由逻辑信号(RT芯片产生的逻辑信号)产生的,它调用通信代码。每当按下Pilots键盘上的按钮时,就会发生中断3,从而执行显示代码。
现在我们有了一套软件子系统,它们由中断激活并相互配合。如果这种设计是在单处理器系统上实现的,那么代码单元就不能同时执行;它们必须以时间共享的方式工作。然而,从现实世界的角度来看,如果它们看起来是并发运行的,那么时间共享就不是问题。另一点需要注意的是,当每个代码单元运行时,它可以完全使用计算机资源;它似乎”拥有”处理器。这意味着,我们在设计软件时,可以把每个功能都看作是在自己的处理器(”抽象”处理器)上运行。
因此,我们在这里看到的是一组单独进程(任务)的明显并发执行,即所谓的 “准并发”。换句话说,通过使用中断,我们可以 “同时 “运行多个任务:这是一种简单或 “穷人 “的多任务处理。本节的主要结论是
- 中断是设计工作的关键使能机制。
- 中断简化了系统的功能设计。
- 中断简化了对不同定时和响应要求的处理。
实际运行时的行为(在大多数情况下)是无法预测或静态分析的。这是并发软件设计中最重要的问题之一,在后面的工作中将会重点讨论。
通过中断驱动任务分配,我们可以将逻辑模型直接映射到代码中,从而保留设计结构。但缺点也是双重的。首先,要有效地应用这种方法,开发人员必须在硬件和软件方面都有很高的技能。其次,任务分时的方式具有很大的限制性;如果由缺乏经验的设计人员使用,所产生的行为和性能可能会大打折扣。
操作系统的核心功能就是消除代码编写者的这一负担(操作系统的所有其他功能都源于此)。它将计算机的复杂性屏蔽在程序员之外,让程序员专注于手头的工作。不再需要中断、定时器、模数转换器等方面的详细知识。因此,计算机可被视为”虚拟”机器,为安全、正确、高效和及时的操作提供便利。换句话说,它让生活变得简单(或至少更容易)。
1.8 实时操作系统的基本特征
考虑到上述因素,我们的硬件和操作系统软件必须支持以下功能:
- 程序的任务结构化。
- 作为逻辑独立单元的任务实现(任务抽象)。
- 操作的并行性(并发性)
- 在预定时间使用系统资源。
- 在随机时间使用系统资源。
- 以最少的硬件知识执行任务。
这些适用于所有操作系统,但这并不意味着所有操作系统的设计方式或目标都相同。
在所有计算机应用中,使用商业操作系统有两大好处:降低成本和提高可靠性。然而,机器的使用方式对其操作系统的设计理念有着深远的影响。例如,大型机环境非常不稳定。任何时候所处理任务的数量、复杂性和规模都可能是未知的(也就是说,一旦它投入使用一段时间后)。在这种情况下,提高吞吐量是首要要求。另一方面,在嵌入式应用中,任务是非常明确的。处理器必须能够在相当明确的时间范围内处理计算机的全部负载(如果不能,系统就会出现真正的问题)。因此,尽管操作系统必须高效,但我们更关注性能的可预测性。此外,运行的可靠性也至关重要。
现在,让我们对问题进行更详细的分析。再次考虑我们的示例系统,它有三个主要任务: JPT控制、飞行记录器接口和飞行员接口。每项任务都可以在单独的处理器上运行,即多任务处理。在这样一个小型系统中,这将是昂贵、复杂的。事实上,大多数嵌入式系统都是这种情况。在本文中,单处理器多任务设计被称为 “多任务 “系统,以区别于多处理器技术(这一定义并不完全正确,但符合通常的用法)。
这样,我们就有了三个独立但相互依存的任务。这就产生了一些有趣的问题,而操作系统的多任务软件可以提供解决方案。首先,我们必须决定任务运行的时间和原因,即”任务调度”。然后,我们必须对任务之间共享资源的使用进行监控,以防止对这些资源造成损害或破坏–“互斥”。最后,由于任务(在本例中)必须能够相互”对话”,因此需要通信设施–“同步和数据传输”。在多任务系统中,有可能出现执行独立功能的任务,即功能独立的任务。一个简单的例子就是在单板数字控制器上实现多个独立的控制通道。这些任务各司其职,无需相互通信。事实上,每项任务都像是在独自使用计算机。但这并不一定意味着每个任务都有自己的资源;可能仍然需要共享系统设施。例如,每个控制通道可能需要通过一条共享数字链路定期向远程计算机报告其状态。在某些情况下,任务之间会争夺这一资源的使用权。通常需要使用互斥功能来解决这种争用问题。
1.9 执行程序、内核和操作系统
牛津计算机词典》对操作系统的定义,即操作系统是 “共同控制计算机系统资源和使用这些资源的进程的一系列软件产品”。然而,要准确定义操作系统的内涵及其构建方式则更为困难。许多操作系统具有相似的总体结构,但在细节上往往存在很大差异。嵌入式操作系统比大型机操作系统更小更简单。下图所示的结构是现代设计的典型结构,由相对较小的软件集组成。请注意,它由一系列定义明确但各不相同的功能组成。
首先看第二个环,即”执行”环。这里集中了控制功能,执行器是所有计算机程序的总控制器。用户任务(程序)通过执行器与其他系统活动(包括其他任务)连接。这与顺序(单”线程”执行)设计截然不同,在顺序设计中,任务操作分布在整个程序中。在这里,每个任务都是单独编写的,通过执行器调用系统资源。执行器本身直接控制所有调度、互斥、数据传输和同步活动。为此,它需要调用内环(内核)提供的详细设施。从某种意义上说,执行器是管理器,内核是执行器。在现阶段,我们不会详细说明执行器/内核组合的具体功能;相反,这些功能将随着我们的工作不断发展。
外环中标有 “应用程序 “的部分不言自明。这些程序通过应用程序接口(API)调用资源,从而使用 RTOS 软件。另一部分是”现实世界接口”,由处理系统硬件的软件组成。这些硬件因设计而异,由标准软件例程驱动。通常包括可编程定时器、可配置I/O端口、串行通信设备、模数转换器、键盘控制器等。任务可以直接访问 I/O 设备;更常见的是通过操作系统提供的例程与现实世界进行交互。
总之,每个任务在编写时都可以把自己当作系统的唯一用户。程序员似乎可以完全访问和控制系统资源。如果需要与其他任务通信,可以使用简单明了的方法来实现。所有系统功能都可以使用标准技术(为该系统开发的技术)访问;不需要任何硬件或底层编程知识。最后,程序员不必采用防御性编程方法来确保系统安全运行。
这些目标的实现程度完全取决于执行器和内核的设计。
参考资料
- 软件测试精品书籍文档下载持续更新 https://github.com/china-testing/python-testing-examples 请点赞,谢谢!
- 本文涉及的python测试开发库 谢谢点赞! https://github.com/china-testing/python_cn_resouce
- python精品书籍下载 https://github.com/china-testing/python_cn_resouce/blob/main/python_good_books.md
1.10 基于任务的软件设计–回顾
从规范到运行基于任务的设计涉及六个步骤。第一个步骤,即第 1步,明确定义要实施系统的范围。这就确立了问题的整体系统级视图,即其整体功能,如图所示。
步骤2确定该系统的主要并发子系统或子功能。在本例中,我们认为整个系统由四个子系统组成。请注意,这是个人的设计决定,完全取决于设计者的观点。
接下来,在第3步中,将指定系统的关键时序和接口方面。这是整个过程的重要部分,对开发实时软件至关重要。开始设计时,这些信息不完整是常有的事,但必须明确指出所有未知因素。
第 4 步包括根据以下想法开发每个任务的设计和代码模型:
- 每个并发子系统都在自己的处理器(或一组处理器)上运行
- 支持处理器将提供所有所需的计算资源(”抽象 “或 “虚拟 “处理器)。
步骤 5 将每个代码单元与特定的抽象处理器关联起来,形成一个抽象任务。这也是 RTOS 首次进入开发流程的地方。要生成抽象任务,我们需要使用RTOS的任务创建软件,通常使用名为”CreateTask”的应用程序接口。它的作用是创建一个命名的任务单元,并将功能代码与该单元连接起来。最基本的代码如下
CreateTask (NameOfCodeUnit, DesignatedNameOfTask);
其中,DesignatedNameOfTask 是操作系统使用的名称,代表抽象任务。
所有任务都必须这样做。对于上面的示例,我们希望在设置代码中找到以下内容(或类似内容):
请注意,这些任务通常会相互合作和交流。
当抽象任务可以使用机器资源时,它就变成了真正的任务。
因此,严格来说,每个任务都描述了单个顺序程序的执行情况。
步骤 6 在真实硬件上运行每个抽象处理器。我们再次使用RTOS软件来启动和运行任务,使用的命令格式为
StartTasks();
请注意,API 及其格式是 RTOS 特有的。
我们的任务集可以在各种硬件配置上运行:
- 单处理器(单处理器解决方案)或
- 多个处理器(多处理器、多处理器或多核单元)。
显然,如果在一台机器上安装多个抽象处理器,它们就必须以时间共享的方式运行。这就决定了操作系统的核心职责:以时间共享的方式运行任务。
当硬件平台由多台实际机器组成时,情况就会复杂一些。我们稍后将在单独一章中讨论这个问题;现在,让我们集中讨论单处理器系统中的 RTOS 问题。
声明:文中观点不代表本站立场。本文传送门:https://eyangzhen.com/242541.html