一. 局部变量、全局变量和反馈节点
LabVIEW使用程序框图接线端对前面板对象进行数据读写。每个前面板对象只有一个对应的程序框图接线端,但有时应用程序可能需要从多个不同位置访问该接线端中的数据。
局部变量和全局变量用于应用程序中无法连线的位置间的信息传递。通过局部变量访问位于单个VI中不同位置的前面板对象。全局变量可在多个VI之间访问和传递数据。
使用反馈节点可保存由上一个VI或循环执行后得到的数据。
二. 局部变量
无法访问某前面板对象或需要在程序框图节点之间传递数据时,可创建前面板对象的局部变量。创建局部变量后,局部变量仅仅出现在程序框图上,而不在前面板上。
局部变量可对前面板上的输入控件或显示件进行数据读写。写入局部变量相当于传递数据至其他接线端。但是,局部变量还可向输入控件写入数据和从显示控件读取数据。实际上,使用局部变量可将前面板对象同时用作输入和输出。
例如,如果用户界面需要用户登录,可在每次新用户登录时清空登录和密码提示框中的内容。通过局部变量,当用户登录时使用局部变量从登录和密码字符串输入控件中读取数据,当用户离开时向这些输入控件写入空字符串。
创建局部变量
右键单击一个前面板对象或程序框图接线端并从快捷菜单中选择创建»局部变量便可创建一个局部变量。该对象的局部变量的图标将出现在程序框图上。
也可从函数选板上选择一个局部变量将其放置在程序框图上。此时局部变量节点尚未与一个输入控件或显示件相关联。如下图所示。
如需使局部变量与输入控件或显示控件相关联,可右键单击该局部变量节点,从快捷菜单中选择选择项。展开的快捷菜单将列出所有带有自带标签的前面板对象。
LabVIEW通过自带标签关联局部变量和前面板对象,因此前面板输入控件和显示控件的自带标签应具有一定的描述性。
三. 全局变量
全局变量可在同时运行的多个VI之间访问和传递数据。全局变量是内置的LabVIEW对象。创建全局变量时,LabVIEW将自动创建一个有前面板但无程序框图的特殊全局VI。向该全局VI的前面板添加输入控件和显示控件可定义其中所含全局变量的数据类型。该前面板实际便成为一个可供多个VI进行数据访问的容器。
例如,假设现有2个同时运行的VI。每个VI含有一个While循环并将数据点写入一个波形图表。第一个VI含有一个布尔控件来终止这两个VI。此时须用全局变量通过一个布尔控件将这两个循环终止。如这两个循环在同一个VI的同一张程序框图上,可用一个局部变量来终止这两个循环。
创建全局变量
从函数选板上选择一个全局变量,将其放置在程序框图上。如下图所示。
双击该全局变量节点可显示全局VI的前面板。该前面板与标准前面板一样,可放置输入控件和显示控件。
LabVIEW以自带标签区分全局变量,因此前面板输入控件和显示控件的自带标签应具有一定的描述性。
可创建多个仅含有一个前面板对象的全局VI,也可创建一个含有多个前面板对象的全局VI从而将相似的变量归为一组。
所有对象在全局VI前面板上放置完毕后,保存该全局VI并返回到原始VI的程序框图。然后必须选择全局VI中想要访问的对象。右键单击该全局变量节点并从快捷菜单中选中一个前面板对象。该快捷菜单列出了全局VI中所有自带标签的前面板对象。右键单击该全局变量节点并从选择项快捷菜单中选择一个前面板对象。
如为全局变量节点创建了一个副本,则LabVIEW将把这个新的全局变量节点与原始变量节点的全局VI相关联。
四. 变量读写
创建了局部或全局变量后,可对变量进行数据读写。默认状态下,新变量将接收数据。此类变量就像一个显示控件,同时是一个写入局部变量或写入全局变量。将新数据写入该局部或全局变量时,与之相关联的前面板输入控件或显示控件将由于新数据而被更新。
变量可配置为数据源、读取局部变量或读取全局变量。右键单击变量,从快捷菜单中选择转换为读取,便可将该变量配置为一个输入控件。节点执行时,VI将读取相关前面板输入控件或显示控件中的数据。
如需使变量从程序框图接收数据而不是提供数据,可右键单击该变量并从快捷菜单中选择转换为写入。
在程序框图上,读取局部或全局变量与写入局部或全局变量间的区别相当于输入控件和显示控件间的区别。类似于输入控件,读取局部变量或读取全局变量的边框较粗。而写入局部变量或写入全局变量的边框则较细,类似于显示控件。
五. 谨慎使用局部变量和全局变量
局部和全局变量是高级的LabVIEW概念。它们不是LabVIEW数据流执行模型中固有的部分。使用局部变量和全局变量时,程序框图可能会变得难以阅读,因此需谨慎使用。错误地使用局部变量和全局变量,如将其取代连线板或用其访问顺序结构中每一帧中的数值,可能在VI中导致不可预期的行为。滥用局部变量和全局变量,如用来避免程序框图间的过长连线或取代数据流,将会降低执行速度。
局部变量和全局变量的初始化
如需对一个本地或全局变量进行初始化,应在VI运行前将已知值写入变量。否则变量可能含有导致VI发生错误行为的数据。如变量的初始值基于一个计算结果,则应确保LabVIEW在读取该变量前先将初始值写入变量。将写入操作与VI的其他部分并行可能导致竞争状态。
要使变量初始化在VI其他部分执行之前完成,可将把初始值写入变量的这部分代码单独放在顺序结构的第一帧。也可将这部分代码放在一个子VI中,通过连线使该子VI在程序框图的数据流中第一个执行。
如在VI第一次读取变量之前,没有将变量初始化,则变量含有的是相应的前面板对象的默认值。
当全局变量或本地变量的值连接至程序框图上的任何位置,变量改变不会引起连线上的值改变。变量的值更改以后,要读取变量的值,才会更新连线上的值。
竞争状态
两段或更多代码并行执行并访问同一部分内存时会引发竞争状态。如果代码是相互独立的,就无法判断LabVIEW按照何种顺序访问共享资源。
竞争状态会引起不可预期的结果。例如,两段独立的代码访问同一个队列,但是用户未控制LabVIEW访问队列的顺序,这种情况下会引发竞争状态。
竞争状态随着程序运行的时间因素而改变,因此具有一定的危险性。操作系统、LabVIEW版本和系统中其他软件的改变均会引起竞争状态。
如改动了VI的时间要素(例如,更新操作系统或LabVIEW版本),请检查访问同一部分数据的并行代码,并使用定时条件来控制哪一部分代码首先执行。
使用局部变量和全局变量时的竞争状态
对同一个存储数据进行一个以上更新动作均会造成竞争状态,但是竞争状态通常在使用局部变量和全局变量或外部文件时出现。以下程序框图显示了一个局部变量造成竞争状态的范例。
该VI的输出,即本地变量x的值取决于首先执行的运算。因为每个运行都把不同的值写入x,所以无法确定结果是7,还是3。在一些编程语言中,由上至下的数据流模式保证了执行顺序。在LabVIEW中,可使用连线实现变量的多种运算,从而避免竞争状态。下列程序框图通过连线而不是局部变量执行了加运算。
提示
如必须在局部变量或全局变量上执行一个以上操作,则应确保各项操作按顺序执行。
如两个操作同时更新一个全局变量,也会发生竞争状态。如要更新全局变量,需先读取值,然后修改,再将其写回原来的位置。当第一个操作进行了读取-修改-写入操作,然后才开始第二个操作时,输出结果是正确的,可预知的。第一个操作读取值,然后第二个操作读取值,则两个操作都修改和写入了一个值。这样操作造成了读取-修改-写入竞争状态,会产生非法值或丢失值。
要避免全局变量引起的竞争状态,可使用功能全局变量保护访问变量操作的关键代码。使用一个功能全局变量而不是多个本地或全局变量可确保每次只执行一个运算,从而避免运算冲突或数据赋值冲突。
循环中的变量行为
当一个变量控制多个并行循环时,循环必须在写入变量后执行,在循环每次执行后读取变量。
当系统重新启动时,循环读取变量之前,必须为变量设置合适的开始条件,避免变量过早停止。
使用局部变量时应考虑内存
局部变量复制数据缓冲区的数据。从一个局部变量读取数据时,便为相关控件的数据创建了一个新的缓冲区。
如使用局部变量将大量数据从程序框图上的某个地方传递到另一个地方,通常会使用更多的内存,最终导致执行速度比使用连线来传递数据更慢。如在执行期间需要存储数据,可考虑使用移位寄存器。
使用全局变量时应考虑内存
从一个全局变量读取数据时,LabVIEW将创建一个数据的副本,保存于该全局变量中。
操作大型数组和字符串时,将占用相当多的时间和内存来操作全局变量。操作数组时使用全局变量尤为低效,原因在于即使只修改数组中的某个元素,LabVIEW仍对整个数组进行保存和修改。如一个应用程序中的不同位置同时读取某个全局变量,则将为该变量创建多个内存缓冲区,从而导致执行效率和性能降低。