约翰·卡本(John A.Carbone)
实时嵌入式系统有望以可预测的实时响应性能运行。但是在某些情况下,启用响应能力的功能实际上会使系统blo肿,并挑战其按需执行的能力。通过抢占阈值调度,开发人员可以减少抢占开销,同时仍使应用程序能够满足实时截止时间。
线程的重要性
在解决抢占阈值调度之前,必须了解一些基本的RTOS功能。 实时操作系统是一种系统软件,可提供服务并管理处理器资源,例如处理器周期,内存,外设和应用程序中断。 实时操作系统通过将软件划分为多个部分(通常称为任务或线程),并创建一个运行时环境,为每个线程提供自己的虚拟微处理器(“多线程”),从而在应用程序必须执行的各种职责之间分配处理时间。这些虚拟微处理器中的每一个都由一组虚拟的微处理器资源组成,例如,寄存器集,程序计数器,堆栈存储器区域和堆栈指针。只有执行线程会使用物理微处理器资源,但是每个线程都像在操纵自己的私有资源一样运行(线程的“上下文”)。
为了获得实时响应,RTOS控制线程执行。设计人员为每个线程分配了一个优先级,以控制在准备好多个线程且未阻塞的情况下哪个线程应该运行。当需要执行更高优先级的线程(与运行中的线程相比)时,RTOS会将当前正在运行的线程的上下文保存到内存中,并还原新的高优先级线程的上下文。交换线程执行的过程通常称为上下文切换。
将控制权转移到另一个线程是RTOS的基本优势。它不是在应用程序软件中嵌入处理器分配逻辑,而是由RTOS在外部完成。这种安排隔离了处理器分配逻辑,并使预测和调整嵌入式设备的运行时行为变得更加容易。
为了提供实时响应,RTOS必须提供抢占,这使应用程序可以立即透明地切换到较高优先级的线程,而不必等待较低优先级的线程的完成。 (不支持抢占的操作环境实际上是在简单,未连接的设备中发现的传统轮询循环技术的另一种变体。)线程的抢占式调度可确保关键线程立即得到关注,以便它们可以满足其实时期限。但是抢先式调度在某些情况下会导致大量的上下文切换开销,这浪费了处理器周期并挑战了实时响应能力。
上下文切换的影响
线程可以具有多种状态:
- READY –线程已准备好运行,但当前未执行指令
- RUNNING –线程正在执行指令
- 已暂停-线程正在等待诸如队列中的消息,信号量,计时器到期之类的东西。
- 终止-线程已完成其处理,无法运行
为线程分配了优先级,这些优先级指示了它们的相对重要性以及如果它们都已准备好运行,它们将获得访问CPU的顺序。通常,优先级是0到N的整数值,可以是0高或0低。每个线程都分配了一个优先级,并且可以动态更改优先级。可以为多个线程分配相同的优先级,也可以为每个线程分配唯一的优先级。
当一个线程正在执行并且另一个更高优先级的线程准备就绪可以运行时,RTOS会抢占正在运行的线程,并使用上下文切换器将其替换为更高优先级的线程。在上下文切换中,RTOS将执行线程的上下文保存在其堆栈中,检索新线程的上下文,然后将其加载到CPU寄存器和程序计数器中,从而将执行线程的上下文从一个切换到另一个。 (请参阅表1。)

上下文切换操作相当复杂,根据RTOS和处理器的不同,可能需要50到500个周期。这就是为什么必须注意优化上下文切换操作并最小化对这些操作的需求的原因。这是抢占阈值调度的目标。
调度和循环
不使用RTOS但包含多个操作或功能(基本上是任务或线程)的应用程序必须提供一种机制,用于运行需要运行的任何功能。可以使用一个简单的顺序循环,也可以使用更复杂的循环,这些循环可以检查状态以确定某个功能是否有工作要做,可以跳过那些没有做的事情并运行那些有工作要做的事情。这些循环是调度程序的形式,但是它们往往效率低下且无响应,尤其是随着线程或函数数量的增加。相反,RTOS调度程序会跟踪在任何时间点运行的活动。
通常,实时调度程序是抢占式的-这意味着它们确保准备运行的最高优先级线程是他们让其运行的线程,而其他线程则等待。 实时操作系统调度程序还可以执行循环调度,这类似于Big Loop(循环),这是循环机制的一种更复杂的形式,在该循环中,单个线程被分配了一定百分比的CPU时间,而不是被允许运行到完成或自愿挂起。 实时操作系统调度程序在需要时执行上下文切换,并使线程可以休眠,放弃其CPU使用,或者终止并保留线程池以等待CPU。有关TraceX分析工具中所示的Express Logic的ThreadX 实时操作系统中的线程抢占的示例,请参见图1。

多线程是一个术语,表示CPU被多个线程共享。在这些系统中,当一个线程到达障碍时,它将CPU分配给其他没有等待任何东西的线程,而不是继续检查继续能力。这样可以更有效地利用原本浪费的CPU周期。一个示例是具有两个线程的简单系统:thread_a和thread_b。如果thread_a正在运行并启动可能需要数百个周期才能完成的I / O操作,而不仅仅是在轮询循环中等待,则可以暂停thread_a直到I / O完成,并且可以允许thread_b使用CPU直到那个时候。这涉及上下文切换。 I / O完成后,将恢复thread_a。与Big-Loop和其他非抢先式调度方法相比,多线程可更有效地利用CPU资源。
抢占挑战
抢占是停止正在运行的线程以便另一个进程可以运行的进程。这可能是中断或正在运行的线程本身执行的操作的结果。在抢占式调度中,RTOS始终运行已准备就绪的最高优先级线程。通常,将保存正在运行的线程的上下文,并在其位置加载另一个线程的上下文,以便新线程可以运行。抢占式调度通常在实时系统和RTOS中找到,因为它可以对外部事件做出最快的响应,即事件发生时线程必须立即运行,或者必须在特定的截止日期之前运行。在最大程度地提高响应速度的同时,开销也很高,因为始终需要进行上下文切换。
抢占会带来潜在的挑战,开发人员必须避免或解决:
- 线程饥饿。当线程因为优先级更高的线程永远不会完成而永远无法执行时,就会发生这种情况。开发人员应避免任何可能导致高优先级线程陷入无休止循环的情况,或者该线程消耗不必要的CPU时间,从而防止其他线程访问处理器的情况。
- 高架. 在具有大量上下文切换的情况下,开销可能加在一起,从而对性能产生重大影响。
- 优先级倒置。当高优先级线程正在等待共享资源,但该资源由低优先级线程持有,该低优先级线程由于中优先级线程的抢占而无法完成对资源的使用时,会发生这种情况。
抢占阈值调度(PTS)
使用抢占阈值调度时,必须超过优先级才能抢占线程。 (图2)抢占阈值调度可防止某些抢占,从而消除了某些上下文切换并减少了开销。

通常,任何优先级高于运行线程的线程都可以抢占它。但是,通过抢占阈值调度,仅当抢占线程的优先级高于运行线程的抢占阈值时,才能抢占正在运行的线程。在完全抢占式系统中,抢占阈值将等于线程的优先级。通过将抢占阈值设置为高于线程的优先级,将不允许优先级介于这两个值之间的线程进行抢占。
在表2的示例中,优先级为20的线程通常会被优先级为19、18、17、16等的线程抢占。但是,如果将其抢占阈值设置为15,则只有优先级高于15(数量较少)的线程才能抢占该线程。因此,处于优先级19、18、17、16和15之间的线程无法抢占,但是具有优先级14和更高(较低数量)的线程可以抢占。抢占阈值是可选的,可以为任何线程,所有线程或不指定线程。如果未指定,则实际上,线程的抢占阈值高于其优先级。但是,如果具有抢占阈值,则线程可以阻止更高优先级的线程进行抢占,该优先级可以达到某个限制,超过该限制将允许抢占。

完全抢占式调度程序可能会引入大量开销,从而降低系统效率。另一方面,抢占阈值调度可以减少上下文切换,并提高性能。
Express Logic,Inc.
www.expresslogic.com
有哪些可用于减少先发性开销的策略?