变量是用来存放数据的,可以用于程序内部甚至是不同程序之间的数据共享和交换。在LabVIEW中,每当新建一个局域变量或全局变量实例都是对原有数据的一次拷贝。也就是说当程序中使用了过多的局域变量或全局变量时,即使没有对这些变量进行写操作,LabVIEW仍然会占用足够的内存来为这些变量创建副本。
事实上,在变量的实际使用过程中,程序员只是用来对某一部分的内存空间进行读写,并且同一时刻也只会由一段程序代码对变量所表示的空间进行访问(这个过程是非常迅速的)。因此,如果程序中需要大量和反复地使用某一变量,就完全没有必要使用局域变量和全局变量。但是如果只是进行少量的数据交换或者对Control控件进行赋值时,还是需要使用局域变量的。
1.1局域变量
LabVIEW中的局域变量(Local Variable)是不能够单独存在于程序中的,它必须依附于某一个控件(Control或者Indicator)。如图 1所示,在LabVIEW的函数选板中选择Functions>>Programming>>Structures>>Local Variable。
图 1 局域变量在函数选板中的位置
将局域变量拖入到VI的背面板中,此时将显示为一个问号,并且VI无法运行(运行箭头断开),如图 2所示。这是由于此时该新建的局域变量还没有与VI界面上的任何控件建立关联。
图 2 未链接的局域变量
在前面板上依次放入一个Numeric控件、Boolean控件和String控件,如图 3所示。
图 3 VI前面板
使用Ctrl+E键切换到背面板,并将鼠标切换到“手型工具”放在局域变量上或者直接使用Automatic工具模式。此时会出现当前VI前面板上所有控件的列表,选择某一个控件就实现了局域变量与控件的链接,如图 4所示。LabVIEW不允许局域变量没有被使用,无论是读还是写均可以,因此局域变量上没有任何连线则VI将无法运行。
图 4 VI背面板
可以在一个VI中建立足够的局域变量进行数据交换,也可以使用局域变量为Control型控件赋值,如图 5所示。
图 5 局域变量的使用
局域变量为同一个VI的数据共享和传输提供了很大的方便,但是由于它必须依附于当前VI中的某一个控件,因此无法在两个不同的VI之间传递数据。
1.2全局变量
全局变量的使用与局域变量相似,但是它并不依附与某一个控件,可以在同一个VI内部或者不同的VI之间进行数据传递(无法在两个独立的exe应用程序之间传递数据)。
全局变量实际上存在于一个vi文件,该文件中没有背面板,里面包含了很多的全局性控件。打开LabVIEW菜单的File>>New…选项,选择Global Variable项可以新建一个全局变量文件。在其中可以加入若干个控件,如图 6所示。[page]
图 6 新建全局变量
将新建的全局变量VI的图标拖入到VI的背面板中,如同调用一个子VI一样,就可以完成对全局变量的引用,如图 7所示。图中使用了2个不同的VI,分别进行全局变量的读和写操作。
图 7 全局变量的引用
1.3局域变量和全局变量的使用小结
可以看出,LabVIEW中局域变量和全局变量的引入为数据的有效共享提供了非常便捷的途径。但是正如前面所述,局域变量和全局变量需要占用大量的内存空间,降低了程序运行的效率,因此在实际过程中应酌情应用。
此外,由于LabVIEW编程环境的并行特性,使得很多程序员在使用局域变量和全局变量时并没有考虑到变量的“竞争冒险”问题。如图 8所示,程序的本意是希望将Numeric的值加1然后再乘以2赋值给Numeric变量,但是由于LabVIEW采用了数据流运行方式,每一段代码的开始运行时间几乎是同时的(并行的),因此导致无法Numeric的输出正确的值。
图 8 变量的竞争冒险
以上举得是一个比较明显的例子,当程序变得庞大而复杂时,这种问题并不容易被发现并且很容易产生。特别是在使用全局变量时,如果程序员没有非常清楚地明晰各个时刻全局变量中的值,那么很容易地读到一些“意料之外”的数据。同时,在使用全局变量时,应该注意变量的初始化操作。虽然,这可以使用LabVIEW的Make Current Value Default菜单项实现,但是仍然推荐使用独立的初始化VI为每一个全局变量显式地赋初值。
1.4Value属性节点和局域变量的效率
众所周知,在LabVIEW中为一个Control赋值有Value属性节点和局域变量2种方式;为一个Indicator赋值有直连、Value属性节点和局域变量3种方式。那么这些方式有哪些区别和联系呢?在实际过程中应该使用哪种方式呢?
为了表示分析这三种赋值方式的区别,使用3个独立的VI进行测试,如图 9所示。可以看出,从时间上来看:Time(直连赋值) < Time(局域变量赋值) < Time(Value属性节点赋值)。这说明Indicator直连赋值是最有效和直接的方式,它只是完成数据的显示;而局域变量赋值需要完成对数据的拷贝,占用事件其次;Value属性节点使用了VI Server技术,它需要完成对前面板控件的调用和刷新,占用时间较长。因此从运行时间上看,对控件的赋值应尽量采用直连或局域变量的方式,尽量少地使用属性节点。
图 9 测试三种赋值方式所占用的时间
1.5功能性全局变量
为了克服局域变量和全局变量的“竞争冒险”潜在危险和复制数据副本的缺点,在LabVIEW中可以使用功能性全局变量代替全局变量的使用。因为全局变量的应用无非是读取和写入操作,因此可以使用LabVIEW的移位寄存器将数据空间强制共享。
本节将建立一个功能性全局变量代替一个Numeric型的全局变量(下载),新建一个VI的前面板如图 10所示,背面板如图 11所示。程序使用了一个只运行一次的while循环,这是为了使用移位寄存器保存变量的值。使用一个枚举控件表示对全局变量的操作(读或者写),而不同的case结构中响应相应的指令。
图 10 功能性全局变量的前面板
图 11 功能性全局变量的背面板
新建一个VI调用上面的VI(称为功能性全局变量),如图 12所示,可以看出能够输出正确的值。
图 12 使用功能性全局变量
由于每次读和写变量时,都是取自于while循环中的移位寄存器,因此能够避免了数据拷贝的问题(当然,全局性功能变量VI不能够设置为Reentrant可重载的)。由于功能性全局变量VI中加入了“错误簇”端子,因此使用ErrorIn和ErrorOut能够很好地避免“竞争冒险”问题。
从理论上说,功能性全局变量能够完全取代传统的全局变量。由于加入了“错误簇”和移位寄存器,避免了数据的重复拷贝。同时,使用枚举型控件(可以设置为Type Def.控件)能够使得整个程序结构更加清晰、明了,实现模块化程序设计的目的。
关键字:局域变量 全局变量 功能型
引用地址:局域变量、全局变量和功能型全局变量
事实上,在变量的实际使用过程中,程序员只是用来对某一部分的内存空间进行读写,并且同一时刻也只会由一段程序代码对变量所表示的空间进行访问(这个过程是非常迅速的)。因此,如果程序中需要大量和反复地使用某一变量,就完全没有必要使用局域变量和全局变量。但是如果只是进行少量的数据交换或者对Control控件进行赋值时,还是需要使用局域变量的。
1.1局域变量
LabVIEW中的局域变量(Local Variable)是不能够单独存在于程序中的,它必须依附于某一个控件(Control或者Indicator)。如图 1所示,在LabVIEW的函数选板中选择Functions>>Programming>>Structures>>Local Variable。
图 1 局域变量在函数选板中的位置
将局域变量拖入到VI的背面板中,此时将显示为一个问号,并且VI无法运行(运行箭头断开),如图 2所示。这是由于此时该新建的局域变量还没有与VI界面上的任何控件建立关联。
图 2 未链接的局域变量
在前面板上依次放入一个Numeric控件、Boolean控件和String控件,如图 3所示。
图 3 VI前面板
使用Ctrl+E键切换到背面板,并将鼠标切换到“手型工具”放在局域变量上或者直接使用Automatic工具模式。此时会出现当前VI前面板上所有控件的列表,选择某一个控件就实现了局域变量与控件的链接,如图 4所示。LabVIEW不允许局域变量没有被使用,无论是读还是写均可以,因此局域变量上没有任何连线则VI将无法运行。
图 4 VI背面板
可以在一个VI中建立足够的局域变量进行数据交换,也可以使用局域变量为Control型控件赋值,如图 5所示。
图 5 局域变量的使用
局域变量为同一个VI的数据共享和传输提供了很大的方便,但是由于它必须依附于当前VI中的某一个控件,因此无法在两个不同的VI之间传递数据。
1.2全局变量
全局变量的使用与局域变量相似,但是它并不依附与某一个控件,可以在同一个VI内部或者不同的VI之间进行数据传递(无法在两个独立的exe应用程序之间传递数据)。
全局变量实际上存在于一个vi文件,该文件中没有背面板,里面包含了很多的全局性控件。打开LabVIEW菜单的File>>New…选项,选择Global Variable项可以新建一个全局变量文件。在其中可以加入若干个控件,如图 6所示。[page]
图 6 新建全局变量
将新建的全局变量VI的图标拖入到VI的背面板中,如同调用一个子VI一样,就可以完成对全局变量的引用,如图 7所示。图中使用了2个不同的VI,分别进行全局变量的读和写操作。
图 7 全局变量的引用
1.3局域变量和全局变量的使用小结
可以看出,LabVIEW中局域变量和全局变量的引入为数据的有效共享提供了非常便捷的途径。但是正如前面所述,局域变量和全局变量需要占用大量的内存空间,降低了程序运行的效率,因此在实际过程中应酌情应用。
此外,由于LabVIEW编程环境的并行特性,使得很多程序员在使用局域变量和全局变量时并没有考虑到变量的“竞争冒险”问题。如图 8所示,程序的本意是希望将Numeric的值加1然后再乘以2赋值给Numeric变量,但是由于LabVIEW采用了数据流运行方式,每一段代码的开始运行时间几乎是同时的(并行的),因此导致无法Numeric的输出正确的值。
图 8 变量的竞争冒险
以上举得是一个比较明显的例子,当程序变得庞大而复杂时,这种问题并不容易被发现并且很容易产生。特别是在使用全局变量时,如果程序员没有非常清楚地明晰各个时刻全局变量中的值,那么很容易地读到一些“意料之外”的数据。同时,在使用全局变量时,应该注意变量的初始化操作。虽然,这可以使用LabVIEW的Make Current Value Default菜单项实现,但是仍然推荐使用独立的初始化VI为每一个全局变量显式地赋初值。
1.4Value属性节点和局域变量的效率
众所周知,在LabVIEW中为一个Control赋值有Value属性节点和局域变量2种方式;为一个Indicator赋值有直连、Value属性节点和局域变量3种方式。那么这些方式有哪些区别和联系呢?在实际过程中应该使用哪种方式呢?
为了表示分析这三种赋值方式的区别,使用3个独立的VI进行测试,如图 9所示。可以看出,从时间上来看:Time(直连赋值) < Time(局域变量赋值) < Time(Value属性节点赋值)。这说明Indicator直连赋值是最有效和直接的方式,它只是完成数据的显示;而局域变量赋值需要完成对数据的拷贝,占用事件其次;Value属性节点使用了VI Server技术,它需要完成对前面板控件的调用和刷新,占用时间较长。因此从运行时间上看,对控件的赋值应尽量采用直连或局域变量的方式,尽量少地使用属性节点。
图 9 测试三种赋值方式所占用的时间
1.5功能性全局变量
为了克服局域变量和全局变量的“竞争冒险”潜在危险和复制数据副本的缺点,在LabVIEW中可以使用功能性全局变量代替全局变量的使用。因为全局变量的应用无非是读取和写入操作,因此可以使用LabVIEW的移位寄存器将数据空间强制共享。
本节将建立一个功能性全局变量代替一个Numeric型的全局变量(下载),新建一个VI的前面板如图 10所示,背面板如图 11所示。程序使用了一个只运行一次的while循环,这是为了使用移位寄存器保存变量的值。使用一个枚举控件表示对全局变量的操作(读或者写),而不同的case结构中响应相应的指令。
图 10 功能性全局变量的前面板
图 11 功能性全局变量的背面板
新建一个VI调用上面的VI(称为功能性全局变量),如图 12所示,可以看出能够输出正确的值。
图 12 使用功能性全局变量
由于每次读和写变量时,都是取自于while循环中的移位寄存器,因此能够避免了数据拷贝的问题(当然,全局性功能变量VI不能够设置为Reentrant可重载的)。由于功能性全局变量VI中加入了“错误簇”端子,因此使用ErrorIn和ErrorOut能够很好地避免“竞争冒险”问题。
从理论上说,功能性全局变量能够完全取代传统的全局变量。由于加入了“错误簇”和移位寄存器,避免了数据的重复拷贝。同时,使用枚举型控件(可以设置为Type Def.控件)能够使得整个程序结构更加清晰、明了,实现模块化程序设计的目的。
上一篇:开发自定义的LabVIEW插件
下一篇:Tree控件的使用