静态优先级模式是实时系统中最常见的调度方法。它的优点在于简单并且能够很好地扩展到大量任务。使用标准的速率单调分析方法Rate Monotonic Scheduling RMS可以简单地分析系统的可调度性如果每个任务的截止时间小于总周期时间那么系统将是可调度的。。5.9.1 抽象Abstract在实时系统设计中紧急性urgency和关键性criticality是两个重要概念。紧急性指的是截止时间的临近程度而关键性指的是按时完成任务在系统功能或正确性方面的重要性。尽管这两个概念明显不同操作系统通常提供的是一个概念优先级。操作系统使用任务的优先级来决定当多个任务准备运行时哪个任务应该优先执行。在嵌入式系统中紧急性(Urgency)和关键性(Criticality)是两个描述任务重要性的属性但它们指涉的方面有所不同。紧急性 (Urgency)紧急性通常指的是任务完成的时间敏感性。一个紧急的任务意味着它有一个严格的截止时间必须在此时间之前完成否则可能导致系统性能下降或者系统行为不正确。实时系统中的许多任务都有高紧急性需要实时响应。举例来说如果嵌入式系统是自动化控制系统那么响应传感器输入以调整机器状态的任务就具有很高的紧急性因为延迟响应可能导致控制失稳或安全问题。关键性 (Criticality)关键性则是指任务对系统整体功能和安全性的重要程度。一个关键的任务是必须始终正确执行因为它的失败可能会导致系统失败或者有安全风险。在设计系统时需要确保关键任务可靠执行即便在系统资源紧张或其他不利条件下也是如此。使用同样的自动化控制系统例子如果有一个任务负责紧急停止全部机器防止伤害操作员的功能那么这个任务就非常关键哪怕它的紧急性不如常规的控制任务。紧急性与关键性的关系在嵌入式系统的设计和任务调度中这两个属性通常需要综合考虑- **高紧急性但低关键性**任务必须快速响应但如果偶尔失败不会造成严重后果。- **低紧急性但高关键性**任务不需要立即完成但任何失败都可能导致严重问题。- **高紧急性且高关键性**这类任务既要快速响应又必须每次都可靠执行。- **低紧急性且低关键性**任务不需要立即完成而且偶尔的失败对系统整体影响不大。在实时操作系统RTOS中任务的调度通常会基于这些属性。例如有些实时系统采用的是混合调度模型它可以同时支持具有不同紧急性和关键性的任务。设计嵌入式系统时理解任务的紧急性和关键性及其间的关系对于确定任务的优先级和系统资源分配至关重要以确保系统既能及时响应也能够维持必要的可靠性。截止时间重要性在嵌入式实时操作系统RTOS环境中任务是系统的基本执行单元通常是响应某种外部事件或满足系统要求的周期性操作。截止时间是指任务必须在指定的时间段内完成的要求。遵守截止时间对于维持整个系统的正常运行至关重要尤其是在安全关键的应用中如医疗设备、工业控制系统和交通控制系统。截止时间类型任务的截止时间有两种基本类型硬截止时间Hard deadlines硬截止时间是绝对不可以错过的。违反硬截止时间可能会导致系统失败有时甚至可能导致财产损失或人身安全事故。例如在自动驾驶系统中任务必须在特定时间之前完成对周围环境的探测否则将导致碰撞。软截止时间Soft deadlines软截止时间允许某种程度的灵活性。偶尔错过软截止时间可能不会造成严重后果但可能会降低系统性能。例如在音频播放系统中任务可以晚于截止时间完成播放但不能晚于指定的最大延迟否则将导致音频播放出现卡顿。截止时间管理管理RTOS任务的截止时间通常包括以下几个方面优先级分配任务根据其紧急性和截止时间的重要性被赋予不同的优先级。系统确保高优先级任务获得处理器时间优先于低优先级任务。调度算法RTOS使用调度算法来确定哪个任务应当在何时执行。常见算法包括最早截止时间优先EDF和固定优先级抢占式调度RMS。时间预算对任务的执行时间做出严格的预算包括最坏情况执行时间WCET的估计以确保任务可以在截止时间前完成。截止时间监测RTOS经常监控任务的执行状态以确保它们能够在截止时间内完成。如果某个任务无法按时完成系统将采取预先规定的补救措施。抢占和上下文切换RTOS常允许高优先级任务抢占正在执行的低优先级任务这要求快速有效的上下文切换技术确保及时响应。资源管理防止优先级反转和死锁等问题系统可能实现优先级继承或优先级上限协议确保低优先级任务不会无限阻塞高优先级任务的执行。结论截止时间对于确保RTOS能够有效响应其管理的实时任务至关重要。通过使用适当的调度算法和资源管理策略RTOS可以优化任务执行降低错过截止时间的风险。这要求开发者具备对任务特性深刻的理解并在系统设计阶段做出精确的时间分析。在设计这样的系统时工程师应当考虑各种情况包括任务中断的处理和对非预期事件的响应策略以确保系统的稳定性和可预测性。5.9.2 问题Problem**实时系统要求行为的执行时间必须精确且可预测才能保持正确的功能。**这一要求来自于各种现实世界的情况例如安全关键系统在发生“事故”之前能够容忍的最大延迟或 PID 控制环的稳定性特性。在非实时的响应系统中PID比例-积分-微分控制器广泛应用于持续控制过程。PID控制器通过设定连续的参数值来实施控制对于监测到的偏差PID系统能够敏感地进行实时纠正确保系统的稳定运作。因此控制器执行的及时性对于系统运行的稳定性具有决定性作用任何执行上的延误都可能对系统的性能和安全造成不利影响。5.9.3 模式结构Pattern Structure图 5-17 展示了该模式的基本结构。每个“活动”对象在图中称为 Concrete Thread都通过调用 createThread 操作并向 Scheduler 传递一个任务执行函数的地址在 Scheduler 中注册。每个 Concrete Thread 会一直执行直到它完成它通过调用 Scheduler::return() 通知 Scheduler被更高优先级的任务抢占将被抢占的任务插入到 Ready Queue 中或者在试图访问被锁定的 Shared Resource 时被阻塞将被阻塞的任务插入到 Blocked Queue 中。图的上部显示了完整的模式。在大多数情况下建模者对调度器及其关联的细节不感兴趣因为它们是由 操作系统提供的。当不需要关注基础设施时则会得到图下半部分所示的简化模式形式。以下是图 5-17 的简要说明Concrete Thread表示一个活动的对象执行特定的任务。Scheduler操作系统中负责管理线程调度的实体。createThread用于创建新的 Concrete Thread 的操作。Ready Queue存储等待执行的 Concrete Thread 的队列。Shared Resource多个 Concrete Thread 共享的资源。Mutex用于保护 Shared Resource 的互斥信号量。该模式的主要特点包括将线程的创建和管理委托给操作系统的 Scheduler。允许 Concrete Thread 被更高优先级的任务抢占。支持线程之间的同步和互斥。简化了并发编程的模型使开发者可以专注于业务逻辑的实现。5.9.4 协作角色Collaboration Roles这里讨论的对象通常由操作系统提供Scheduler、Mutex、Ready Queue和Blocked Queue。Abstract Thread这是一个抽象类为Concrete Thread提供了一个非实例化的超类定义了线程的基本接口。Concrete Thread这是一个具体的线程类它是Abstract Thread的子类代表实际执行的线程。Scheduler调度器对象负责初始化系统加载所有任务并根据任务的优先级来运行它们。Mutex互斥量对象用于保证线程安全防止多个线程同时访问共享资源。Ready Queue就绪队列存放准备好执行的任务的TCB任务控制块引用。Blocked Queue阻塞队列存放因等待资源而被阻塞的任务的TCB引用。Task Control Block (TCB)任务控制块包含了线程的调度信息如优先级、默认起始地址、当前入口地址等。Timer计时器对象向Scheduler发送周期性的时钟信号告知何时切换当前活动的任务。Shared Resource共享资源对象是由一个或多个线程共享的对象必须通过互斥量来保护以确保数据完整性。抽象线程 (Abstract Thread)抽象不可实例化超类用于创建具体线程。与调度器关联。具体线程作为子类拥有与抽象线程相同的调度器接口确保接口兼容性。阻塞队列 (Blocked Queue)任务控制块 (TCB) 引用优先队列。当任务被阻塞即需要资源可用才能执行时其引用会被放入此队列。当任务解除阻塞所需资源可用时它将被从阻塞队列中移除并放入就绪队列。具体线程 (Concrete Thread)Concrete Thread是一个“活动”对象它包含了一些被动“语义”对象用于执行系统实际工作。具体线程是抽象线程的可实例化子类。互斥信号量 (Mutex)互斥访问信号量对象一次只允许一个调用者访问共享资源。共享资源的操作在调用相关服务时调用它在开始服务之前锁定服务完成后解锁。当服务被锁定时尝试调用服务的线程将被阻塞直到互斥信号量处于解锁状态。互斥信号量向调度器发送信号通知调度器当前活动线程尝试调用互斥信号量并提供互斥信号量 ID 用于以后释放时解锁和入口点线程继续执行的位置。就绪队列 (Ready Queue)存储当前准备运行的任务的 TCB 引用。只要就绪队列中最高优先级的任务比当前运行任务的优先级更高或当前运行任务终止则该任务的 TCB 引用将从就绪队列中移除其对应的任务开始执行。如果一个线程正在执行更高优先级的线程被放入就绪队列则当前执行的线程会被抢占即停止执行并重新放入就绪队列高优先级线程优先执行。调度器 (Scheduler)根据简单规则始终运行就绪队列中优先级最高的线程协调多个线程的执行。一些调度器可能比这更复杂但这是基本规则。当“活动”线程对象被创建时它或其创建者调用 createThread 操作为“活动”对象创建一个线程。调度器执行此线程时它会调用 StartAddr:address除非线程被阻塞或抢占则调用 EntryPoint 地址。共享资源 (Shared Resource)由一个或多个线程共享的对象。为了在所有情况下系统都能正常运行所有共享资源要么是可重入的意味着来自同时访问的破坏不会发生要么必须受到保护。通过互斥访问信号量进行保护将在受保护调用模式中讨论。对于受保护的资源当线程尝试使用资源时会检查关联的互斥信号量如果被锁定调用任务将被放入阻塞队列任务将被终止其重新进入点记录在 TCB 中。堆栈 (Stack)每个抽象线程都有一个用于返回地址和传递参数的堆栈。这通常在应用程序线程的汇编语言级别是显式的但它是调度基础设施的重要组成部分。任务控制块 (TCB)TCB 包含与其对应的线程对象相关的调度信息。这包括线程的优先级、默认启动地址以及被抢占或阻塞时的程序入口地址。调度器为每个现有线程维护一个 TCB 对象。注意TCB 通常也引用该线程的调用和参数堆栈但图 5-17 中未显示该细节。5.9.5 结果Consequences在设计实时系统时紧急性urgency和关键性criticality是两个重要概念。紧急性指的是截止时间的临近程度而关键性则指满足截止时间在系统功能或正确性方面的重要性。操作系统通常使用任务的优先级来处理这两个问题即总是运行当前准备就绪的最高优先级任务。静态优先级模式是操作系统任务调度的一种普遍方法。它在 UML 中使用“活动”对象来模拟线程并可针对不同调度策略进行调整。静态优先级的分配在这种模式中任务优先级是在设计阶段就分配好的这意味着系统在运行时无法动态调整优先级来适应变化的条件。对于大多数系统而言由于设计时已确保系统能在最坏情况下得以调度所以此种固定优先级分配方式通常足够。但这也局限了该方法的可扩展性。如果系统环境和系统响应是高度可预测的则静态优先级可以应用于各种规模的系统。最常用的优先级分配策略是 RMS确定优先级的最常用策略是基于速率的单调调度RMSRate-Monotonic Scheduling。RMS调度算法是一种静态调度算法它根据任务的执行周期来分配任务的优先级。RMS 算法的基本假设如下任务是周期性的、可抢占的所有任务都是周期性的即每个任务都有固定的执行周期。任务在周期内执行周期结束后进入就绪状态等待下一个周期的执行。所有任务都是可抢占的即高优先级的任务可以随时抢占低优先级的任务的执行。截止时间可以发生在任务周期内的任何时间点所有任务的截止日期可以发生在周期的任何时间点。RMS 算法保证所有任务都能在截止日期之前完成执行即使截止时间与周期不相匹配。在这些条件满足的情况下RMS 根据任务的周期长度分配优先级——周期越短优先级越高。这种调度策略被证明是最优和稳定的。如果一组任务可以使用其他策略进行调度那么也能使用 RMS 调度。在超载情况出现时其稳定性体现在能预测出优先级较低的任务会失败。当 RMS 的第一个假设不成立时可以使用以下方法来分配优先级使用事件驱动型任务的最短到达间隔作为周期使用其他调度策略当 RMS 的第二个假设不成立时可以使用截止时间单调调度DMS来分配优先级。在 DMS 中任务优先级的分配基于截止时间的长度而不是任务的周期。5.9.6 实现策略Implementation Strategies步骤识别对象:首先从协作对象中找出“活动对象”即需要多任务处理的对象。任务分配:为每个“活动对象”分配任务。对象组合:将协作对象中的“被动对象”不需要主动操作的对象通过组合关系融入“活动对象”内部。线程安全:调整“活动对象”之间的关联确保线程安全。可以采用之前提到的“Rendezvous 模式”实现资源共享同步或使用互斥锁等机制防止冲突。这个模式涉及到的大部分基础设施可由实时操作系统提供包括阻塞队列、就绪队列、调度器、互斥锁和任务控制块。因此如果您使用现有操作系统来实现多线程模式只需关注“抽象线程”、“具体线程”和“共享资源”这三个核心部分。当然如果您需要自己编写调度器则需要同时构建操作系统相关对象。总结:通过遵循这些步骤并选择合适的工具您就能够构建安全高效的多线程程序。希望这篇简要说明能帮助您理解和应用多线程模式。5.9.7 相关模式Related Patterns虽然该模式应用广泛但在管理多个并发线程时通常还需要其他模式来解决额外问题。具体而言以下模式可与之协作信息同步和共享消息队列模式、受保护调用模式、Rendezvous 模式等解决线程间高效安全地交换信息和同步行为。并发资源管理静态分配模式、固定大小缓冲区模式、优先级继承模式等有效管理共享资源和线程对资源的访问。动态优先级模式作为一种可选的替代方案提供不同的线程调度策略。通常情况下线程间需要共享资源。为了保证资源的完整性常见的一种实现方式是阻塞策略当优先级较高的线程需要占用低优先级线程持有的资源时高优先级线程会一直处于阻塞状态直到资源释放。然而这种简单方式可能会导致系统无法调度陷入「无限优先级反转」的困境。针对这一问题优先级继承、最高锁定人和优先级上限协议等资源共享模式提供了专门的解决方案。5.9.8 示例模型Sample Model图 5-18 展示了一个多线程模式的示例模型它基于图 5-17b 的简化形式。在这个模型中系统创建了三个线程即主动对象每个主动对象都在其构造函数中创建了一个操作系统线程来执行任务。主动对象之间可以通过被动对象进行间接通信。被动对象是指在其所在主动对象线程中执行的对象。数据采集线程 (DataAcqThread) 和过滤线程 (FilteringThread) 共享原始数据 (RawData) 资源使用互斥信号量 (mutex semaphore) 来序列化访问防止数据损坏。过滤线程和显示线程 (DisplayThread) 共享处理后的数据 (CookedData) 资源同样使用互斥信号量来保护数据完整性。三个线程以不同的静态优先级运行数据采集线程优先级最高显示线程次之过滤线程最低。调度器决定何时运行每个线程。执行流程图 5-18b 展示了该模型的一个典型执行流程A. 调度器Scheduler运行显示线程DisplayThread。显示线程DisplayThread从处理后的数据资源(CookedData) 中获取数据。B. 显示线程DisplayThread执行完毕。C. 调度器Scheduler运行过滤线程(FilteringThread) 。过滤线程(FilteringThread) 计划获取原始数据(RawData) 进行过滤然后将结果存储为处理后的数据 (CookedData)。然而在使用原始数据(RawData) 资源期间它被更高优先级的任务数据采集线程 (DataAcqThread)抢占。D. 调度器Scheduler运行数据采集线程(DataAcqThread)。由于其优先级高于过滤线程(FilteringThread) 过滤线程(FilteringThread) 被抢占。数据采集线程(DataAcqThread)尝试将数据写入原始数据(RawData)资源。E. 原始数据(RawData)上的互斥信号量图中未显示阻止数据采集线程向原始数据(RawData)资源写入数据这是为了保护资源的完整性。F. 由于更高优先级的任务被阻塞过滤线程(FilteringThread) 被允许继续运行直到它释放原始数据(RawData)资源。原始数据(RawData)资源释放后数据采集线程(DataAcqThread)解除阻塞立即抢占过滤线程(FilteringThread)。数据采集线程(DataAcqThread)执行完毕后过滤线程(FilteringThread)才被允许继续。它更新处理后的数据 (CookedData)资源然后终止。要点总结该模型展示了三个线程如何共享资源并协作完成任务。线程间的优先级设置影响了它们的执行顺序高优先级线程可以抢占低优先级线程的资源。互斥信号量等同步机制用于保护共享资源的完整性防止数据损坏。