基于优先级的调度模式
- 更新时间2025-05-20
- 阅读时长7分钟
本章节讲解LabVIEW Real-Time模块创建和调度线程时如何处理优先级和执行系统。理解基于优先级的调度模型之后,可利用LabVIEW Real-Time模块创建确定性应用程序。
线程、优先级和执行系统
LabVIEW将计算机的各种复杂操作简化为直观的图形化编程界面,是一种结构化的数据流语言。下列几个关键概念定义有助于理解LabVIEW的并行任务优先级调度。
- 线程 – LabVIEW Real-Time模块的并行基本单位。线程中的任务按顺序执行,单个线程独立运行。
- 调度器 – 操作系统用于调度线程的算法。调度器用于决定特定时间各个CPU上运行的线程。
- 运行队列 – 准备调度的线程队列。
- 抢占式调度 – 调度器中断低优先级线程,高优先级线程准备运行的过程。
- 轮叫调度 – 调度器在同等优先级的几个线程之间定期切换,促进处理器时间平等共享。
- 执行系统 – 相关线程的池。使用“VI属性”对话框的“执行”页配置VI的执行系统。
- VI优先级 – 在“VI属性”对话框的“执行”页上分配VI的优先级。
- 定时循环优先级 – 使用优先级输入或“配置定时循环”对话框为定时循环分配的优先级。
- 操作系统优先级 – 实时操作系统分配给线程的优先级。LabVIEW根据VI或定时循环的优先级分配给各个线程的优先级。
- 实时优先级 – LabVIEW VI可用的最高优先级。实时优先级线程的优先级高于调度器本身。因此,实时优先级线程总是运行至结束或阻隔。
- 优先级继承 – 线程暂时承担调用线程优先级的过程。优先级继承有助于避免优先级倒置。
- 抖动 – 程序的执行事件没有满足确定性预期。
下图是LabVIEW中优先级和执行系统的概览。
从上面的图示中,可以得出:
- 执行系统独立于优先级。只有在线程轮询,且不按照执行系统排列线程的优先级时,LabVIEW才使用执行系统。对于每个执行系统,LabVIEW在每个优先级上创建四个线程。该规则适用于多核系统,例如,在双核系统上,LabVIEW在每个执行系统的优先级上可创建8个线程。因为每个执行系统的线程数量是有限的,所以需平衡执行系统的分配。如在一个执行系统中分配太多VI,VI就不得不共享线程,从而影响了VI并行机制。
- 定时结构的优先级位于高优先级和实时优先级VI之间。
- 将并行代码放在一个定时结构中,LabVIEW将依顺序执行代码,因为每个定时结构只包含一个且仅有一个线程。
- LabVIEW Real-Time模块系统包括许多与组成LabVIEW VI的线程并行运行的系统线程。这些系统线程按不同的优先级执行。例如,若存在NI扫描引擎线程,默认运行优先级高于实时线程。
优先级继承
LabVIEW使用优先级继承来避免优先级倒置。如子VI的优先级低于调用方VI的优先级,两个VI都在一个执行系统中运行,子VI将继承调用方VI的优先级。如子VI的优先级高于调用方VI的优先级,子VI保持原有优先级。
实时操作系统(RTOS)也有优先级继承。如低优先级线程占用了高优先级线程所需的资源,实时操作系统会暂时提高占有共享资源所需的优先级。这样,高优先级线程就可占有所需的资源。
实时优先级
有两种类型的实时优先级线程:
- 设置为实时优先级的VI – 设置为实时优先级的VI,运行优先级高于调度器本身。因此,实时优先级的VI一直运行到结束或中断,例如,定时函数或外部事件发生。
- 定时结构 – 定时结构可被另一个较高优先级的定时结构或设置为实时优先级的VI中断。
定时结构优先级
LabVIEW使用两种优先级机制,VI优先级和定时结构优先级。这两种优先级机制既相互独立,又相互关联。定时结构优先级是数值,数值越大,表示相对于终端上的其他定时结构优先级越高。但是,所有定时结构优先级都在高和实时VI优先级上。
使用优先级机制时避免错误
NI建议仅在应用程序中使用一个优先级机制,使用范例如下:
- 如应用程序使用定时结构,将所有VI设为普通优先级。
- 如应用程序使用实时优先级的VI,请勿将定时结构置于实时优先级的VI中。
在应用程序中使用一种优先级策略,应用程序更易于理解,并且不容易出错。
调度
调度就是判定指定时间运行哪个任务的进程。调度是所有操作系统的核心任务,尤其是实时操作系统(RTOS)。除VI引发的线程之外,实时终端运行多个OS并以不同的优先级驱动线程。为确保任务根据定时要求执行,需了解LabVIEW Real-Time线程调度的规则。
基本的RT调用规则
当一个新的线程进入运行队列时,LabVIEW Real-Time调度器进行下列操作:
- 在不同优先级的线程之间进行抢占式调度。
- 在同等优先级的线程之间进行轮叫调度。
- 实时优先线程通常保持运行直至结束。
LabVIEW Real-Time模块调度工作原理
在任何给定时间,系统中的线程为“运行”或“阻止”两种状态中的一种:
- 运行 – 线程位于运行队列中,即线程执行就绪或正在执行。
- 阻止 – 线程必须等到某些事件(例如,I/O操作完成或定时函数)发生才能执行。
线程开始执行后,除非发生下列条件,线程才停止运行:
- 线程可被While循环中的等待VI、定时循环的内置定时机制,或读取变量(超时方式)函数等阻止函数阻止。
- 线程被更高线程中断。
- 线程完成执行。
线程取消阻止后,重新进入运行队列。运行队列按优先级排序,当线程进入队列时,线程排在低于其优先级的所有线程之前。如进入运行队列的线程比当前运行的线程优先级更高,高优先级线程要么在另一个CPU核上运行,要么中断当前运行的线程,叫做抢占式调度。
抢占式调度
抢占式调度是根据线程的相对优先级对线程的执行进行排序。如某线程的优先级比当前运行线程的优先级高,该线程进入运行队列时,调度器会中断当前线程,较高优先级的线程可立即执行。中断的线程返回运行队列。
轮询调度
轮叫调度是指在不同的线程之间切换,每个线程被分配的CPU时间大致相等。在轮叫调度中,调度器按固定时间间隔中断和切换线程,记录每个线程分配的CPU时间。
LabVIEW Real-Time模块在同等优先级的线程之间执行轮叫调度。但是,LabVIEW Real-Time模块不会在实时优先级的VI之间执行轮叫调度。
根据定时要求设置循环优先级
根据循环的重要性设置各个循环的优先级,该方法虽然直观,但是会导致抖动。不要根据任务在应用程序中的重要性,而要根据该任务满足特定时间要求的重要性来设置循环的优先级。例如,一个数据记录应用程序,包含数据采集循环和数据记录循环,用户可能会把数据记录循环设置为较高的优先级。但是,数据采集必须按照固定间隔进行,否则,容易丢失数据点。只要最终将各个数据点记录到磁盘,何时记录某个数据点并不重要。在该情况下,尽管应用程序的目的在于记录数据,仍可将较高的优先级分配给数据采集循环。