状态机
循环条件结构
循环条件结构是指在循环结构内嵌套了一个条件结构这样的一种复合结构。它是 LabVIEW 中常见的程序结构模式之一。
假设需要编写这样一个测试程序,它有多项测试任务:任务 A、任务 B …… 程序需要顺序执行每一个测试任务。这是一个典型的顺序结构的程序,我们可以采用顺序结构程序的编写方法:
如果程序要求更复杂一些,简单的顺序结构就不够灵活了。比如,有多种产品需要测试,但每种产品的测试流程不一样,有的产品需要测试任务 ABC,有的则需要按顺序测试任务 CDA 等。虽然,可以针对不同产品编写不同的测试程序,但那样需要维护太多不同程序,维护成本太高。
一个更为有效的方法是把测试任务序列作为测试程序的输入,程序根据用户每次指定的测试任务顺序来调用测试任务。这个程序可以使用循环条件结构来完成:
这个程序中的“任务队列”应该是一个输入控件,用户不需要改动程序,只需在主界面选择一组测试任务,就可以改变它的输入值。这里为了便于演示,把它变成了一个常量。“任务队列”是一个数组,元素按照任务执行的顺序排列。在程序运行时,循环每迭代一次,循环结构就从“任务队列”中取出一个任务,然后由条件结构根据该任务的名称选择并进入相应的分支,执行该任务。
单状态传递的状态机
假设测试程序的逻辑更复杂一些,如要求根据某一测试任务的运行结果再决定选择下一个测试任务。这样就要求循环迭代一次后,才产生下一次迭代条件结构的选择条件。我们可以把程序再改进如下:
程序开始时,首先指定一个初始任务。条件结构处理完初始任务后,根据当前结果设定下一个任务。由于不能预计循环需要迭代几次,所以需要使用 while 循环。并且,条件结构还多了一个“结束测试”分支,这个分支用于退出 while 循环,它负责把“真”值传递给循环停止条件接线端。
改进后的这个程序结构模式也被称为状态机。状态机中具有若干个状态,它在某一时刻仅处于一个状态,在收到某事件或数据后跳转到另一状态。在程序中,每个条件结构中的分支表示一个状态,循环下一次迭代,就跳转到另一个状态中去了。
状态机是一个比较常用的结构模式,所以 LabVIEW 的新建 VI 模板中提供了状态机 VI 的模板。需要使用这一模板时,在 LabVIEW 的启动界面选择它:

或打开 VI 的 "文件 -> 新建" 菜单,在弹出的新建对话框中,选择“VI-> 基于模板 -> 框架 -> 设计模式”中的“标准状态机”:

队列状态机 (Queued State Machine, QSM)
上面展示的状态机中,每一个状态结束前,它只能指定下一个状态。但在实际程序中,有时执行完一个分支的代码,就可以根据当前数据,确定后两次甚至更多次迭代中需要执行的分支。完成这种功能需要用到队列。这种结合了队列的状态机结构,在 LabVIEW 开发中被称为队列状态机 (Queued State Machine)。
队列是一种数据结构,队列中可存放多个类型相同的数据。它保证了数据先进先出。队列的行为就像是排队买票,数据进入队列,就好像顾客进入排队,先排进去的顾客一定会被先处理,然后先出队伍。利用队列,我们可以一次性将未来需要执行的多个状态(任务)按顺序“压入”队列中,状态机的主循环只需不断从队列头部取出下一个状态去执行即可。
LabVIEW 有关队列操作的函数在函数选板“编程 -> 同步 -> 队列操作”中。LabVIEW 中的队列与其它常用的数据结构(比如 array, map, set)都不太一样,它在最初设计时,主要是为了在线程间传递数据,而不是为了存储数据。当然这并不妨碍我们在这里用它来保存需要跳转的状态。本书在传引用一节中,还会对队列做详细介绍。
使用队列对状态机进行改进后程序如下:

程序首先创建一个队列,用于保存程序中需要跳转到达的状态,并在进入循环前,把初始状态加入队列。循环每次迭代,首先从队列中取出下一状态,用于选择条件结构的分支。在一个分支处理完毕后,再把后续要跳转到的多个状态加入队列。