静态优先级模式是实时系统中最常见的调度方法。它的优点在于简单,并且能够很好地扩展到大量任务。使用标准的速率单调分析方法(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
确定优先级的最常用策略是基于速率的单调调度RMS(Rate-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)资源,然后终止。
要点总结
- 该模型展示了三个线程如何共享资源并协作完成任务。
- 线程间的优先级设置影响了它们的执行顺序,高优先级线程可以抢占低优先级线程的资源。
- 互斥信号量等同步机制用于保护共享资源的完整性,防止数据损坏。
7883



被折叠的 条评论
为什么被折叠?



