- 易迪拓培训,专注于微波、射频、天线设计工程师的培养
LABVIEW的深入探索之全局变量的优劣
sandan0615:
在保证数据不冲突的情况下可以对全局变量写操作吗?
RTRT,各位高手解释下,我在陈树学老师的宝典里看到说在程序里要避免对全局变量进行写操作。
czhen:
当然可以
不行的话,要它干啥
wyb4993:
我有一个自动化测试程序,里面有很多LabVIEW全局变量,可以读和写。是前一任离职的兄弟留下的。目前运行很正常。
关于慎用全局变量的问题,很多编程语言方面的书籍都会提及,NI论坛上有一个长达十几页的帖子专门讨论的这个问题,非常详细。
其中不仅仅涉及全局变量,还提及了许多解决问题的技巧。
下面我大概翻译一下其中重要的部分,希望有助于理解如何正确使用全局变量。帖子很长,我需要用几天的时间陆续给大家介绍。
-------------------------------------------------------------------------------------------------------------------------------
TBOB:
不止一次地看到人们在抱怨,全局变量是罪恶之源,根本就不应该使用它们。但是我不认为这个结论是显而易见正确的。我希望能听到一次有关全局变量的严肃认真的讨论。论坛中的朋友们很多都提到了他们都正在编程中使用全局变量。
先从全局变量的有点谈起。一般来说,全局变量是公认的在各个VI之间传递数据的有效方法,比起其它方式的全局变量(个人意见)更容易管理,因为假如我们使用了一个簇作为全局数据,我们没有办法确定在何处使用了它们,可能需要自己创建一个文件记录它们使用的位置。但是全局变量则不然,通过全局变量的右键快捷菜单,我们可以很容找到引用全局变量的位置。
使用全局变量有两个不利之处,其一,引用全局变量需要创建数据的拷贝,这可能会导致潜在的竞争条件或者导致数据的丢失。其二,使用全局变量会中断数据流程。
所以,我对那些反对使用全局变量的人士提出一个问题---你们在应用全局变量时考虑了全局变量是否有效的问题了吗?
如果对全局变量只有一个写入者,而有多处读取者,您仅仅关心变量的最新写入值的情况下,您怎么能断定不能使用全局变量呢?
---------------------------------------------------------------------------------------------------------------------------
Darren:
全局变量在某些情况下是非常好用的。如果我有一些静态数据,这些静态数据必须在多个VI中共享,这种情况下,我会使用全局变量存储这些静态数据。(所谓静态数据就是不需要改变的数据,常量)。最常见的例子是需要给用户提示的文本字符串。如果我有一个非常复杂的GUI,需要在很多地方向用户提示文本信息。我会创建一个全局变量VI,把这些字符串创建为全局变量,并且按照字母顺序排序(通过设置TAB ORDER)。这样我们需要在程序框图中使用全局变量时,直接拖入并选择我们需要的。这种方法可以很容易使我们的应用程序本地化,因为所有的显示字符串集中在一个VI之中,而不是散布在各个VI之中,很容易集中处理。
我另外一次使用全局变量是在一个子面板应用中,因为我的子面板中的VI不需要和主VI交换信息,所以我将子面板VI中的数据写入全局变量,供应用程序其它部分读取。因为不需要同步化以及只有子面板中的VI写入数据,保证了只有一个写入者,这恰恰是全局变量的最佳工作方式。
--------------------------------------------------------------------------------------------------------------------
TBOB:
很高兴能看到同人谈及如何恰当地使用全局变量,而不是简单地说完全不要使用全局变量。我们更应该强调如何恰当地使用全局变量,帮助人们了解数据竞争是如何产生的,以及如何避免竞争情况出现。
我大多数使用全局变量时,是把全局变量作为常量来使用的,比如保存一个GPIB的地址。它们一旦创建后就永远不会再次写入更改,这种情况下,绝对不会出现数据竞争的情况。或者在生产消费者模式中,生产者写入全局变量,而消费者读取全局变量。这种情况下,读的时机是非常重要的。我使消费者不断查询全局变量,是否和原来的值发生变化。换句话说,消费者在数据更新之前可能读取了两次,当然并不很理想。
对于局部变量也是如此,总有它们合适使用的场合,但是必须小心可能会导致的问题。教会人们发现问题和解决问题好于仅仅说避免使用它们。
--------------------------------------------------------------------------------------------------------------------------------
Jasonhill:
我也经常看到要求禁止使用全局变量,在合适的条件下,使用全局变量还是非常有用的。但是程序员还是会不自觉地倾向于滥用它们,任何变量(全局变量、局部变量、LV2全局变量)在使用时需要格外小心,“连线”还是最安全的。
我非常讨厌上下或者左右堆积大量的控件,在程序框图中多达20几个层叠顺序结构中,到处散布一些全局变量或者局部变量。
至于你提及的生产者消费者模式,我还是愿意使用队列来完成,使用队列可以使我们不需要考虑读的时机问题。
-----------------------------------------------------------------------------------------------------------------------------T
TBOB:
在生产者消费者模式中,使用队列(我也倾向于使用队列,而不是变量)同样存在问题。消费者可能运行速度高于消费者,此时可能读回空数据,必须在编程中检查是否是否读回空数据。
----------------------------------------------------------------------------------------------------------------------------
TST:
在生产消费者模式使用队列时,我愿意使用超时的默认值-1,这意味着消费者在没有数据时不会执行一个循环,也不需要检查超时是否发生了。
------------------------------------------------------------------------------------------------------------------------------
TITOU:
真是个好题目!
全局变量是魔鬼吗?------我愿意这样回答:不是,只要你遵循了全局变量的工作规则。
我经常建议避免使用全局变量,但是的确在特定的场合,我还是会使用全局变量,因为使用全局变量的确非常方便。
使用但不要滥用。
--------------------------------------------------------------------------------------------------------------------------------
ROBERT:
即使在基于文本的编程语言中,采用封装和抽象本身就倾向于不使用全局变量。理想的结构应该是这样的,如果函数需要一个变量,必须从函数的调用者哪里接收这个变量。尽管如此,即使在这样的编程环境中,还是需要有限度的和合理的利用全局变量。正如上面的帖子中指出的那样,一个写入者,多个读取者。亦或需要在整个程序应用,但是不需要改变的场合。
我经常采样下面的方式。在程序启动时,先运行一个配置函数或者“参数设置”函数,此时没有其它的进程工作,数据采集也尚未进行。此时为程序的其它部分创建全局变量是合理的。 [p]
------------------------------------------------------------------------------------------------------------------------
KEVIN:
我在程序开发时,习惯于在多个消费者情况下使用“通告”。通常情况下,只有一个生产者。但是像全局变量情况,可能会有几个“潜在”的生产者。
对于使用通告,消费者可以进行选择。通告可以不管消费这是否已经消费了先前的数据,随时查询最新的数据,这类似于全局变量。通告也可以一直等待,直至有最新更新的数据,避免不断的轮询数据,加重CPU的负担,这个是全局变量无法实现的。
----------------------------------------------------------------------------------------------------------------------------
BEN:
很抱歉没能早点参与这个话题的讨论。我并非求全责备,但是全局变量存在下列主要问题:
1、数据拷贝
2、利用线程
3、对于一个写入者,多个读取者,OK.但是这要求开发者必须确认只有唯一一个写入者。这对一个拥有800多个VI,有些是动态载入的情况下,是很难做到的。
4、灵活性 。如果你使用一个LV2型全局变量,需要的情况下,你可以很安全地添加新的新的写入者。在编写大型应用时,这的确是令人头疼的问题。
5、性能。LV2全局变量可以很容易重用缓存,全局变量不行。
-----------------------------------------------------------------------------------------------------------------
RAY:
我同意大家的看法。我通常用全局变量保持静态数据,比如IP地址。
-------------------------------------------------------------------------------------------------------------------------
TST:
VI之间传递数据有几种方法。
首先,可以通过函数连接器的端子连线数据,这是LABVIEW传递数据最有效的方法,同时也最安全,最容易理解。但是对于一个正在运行的VI,想传入数据,这种连线方法无能为力。
第二,有一种LV内置的全局变量(上面讨论的),这是VI之间传递数据最快捷的方法。同时非常易于管理,你很容易可以找到引用它们的位置。主要不利之处在于,多处创建全局变量时,都会生成全局变量的数据拷贝。这会引发数据竞争。
第三,通过LV2全局变量,LV2的命名是根据变量出现的LABVIEW版本号,也有称作功能全局变量、函数全局变量或者USR全局变量。LV2全局变量是由一个仅循环一次的VI构成的,循环结构中包含未初始化的移位寄存器(USR)--USR用于在多次运行VI之间保持值。如果该VI设置成不重入方式,那么在不同位置多次调用这个VI时,USR可以共享数据。
LV2全局变量的优点是只存在一个数据拷贝,而且是内在的锁定机制。另外的优势在于可以通过添加代码提高它的性能,因为可以用于拥有自己的存储值,这是非常有用的。
第四,利用队列(高级函数选板,同其它同步函数在一起)。队列的常规用法是在队列中保存产生的数据,但是队列也有一种特殊的方法,使用队列作为全局变量。这种方式队列中只保存一个元素,每次调用队列开始时要取出元素,此时其它要使用队列的地方必须等待,直至正在调用队列的VI完成,把元素加入队列。利用队列构建的全局变量速度高于LV2全局变量,但是比内置的全局变量慢。
使用全局变量时,有几点必须指出,供参考。
1、打断了数据流。这是非常重要的一点,因为打断了数据流会导致程序难于理解,难于调试和排错。
2、竞争。当有多个位置写入全局变量时,非常容易导致数据丢失。
------------------------------------------------------------------------------------------------------------------
BEN:
使用全局变量对于大型应用程序的开发和升级非常危险。我再次强调全局变量是魔鬼,是魔鬼。
---------------------------------------------------------------------------------------------------------------------------
TBOB:
我再次重复几周前说过的话,全局变量不是魔鬼,不恰当地使用全局变量才是魔鬼。
我已经在测试测量领域开发了一些大型应用程序,我利用全局变量保存所有仪器的GPIB地址和PCI卡的名称,这些东西绝对不会在运行中写入,总是在读取。我就不明白了,这种情况下我用全局变量有错吗?
某些情况下,全局变量对简化程序是必须的。我使用全局变量类似于C语言的常量定义。
-----------------------------------------------------------------------------------------------------------------------
RAY:
我偶尔会使用全局变量,使用场合与TBOB类似。
----------------------------------------------------------------------------------------------------------------------
TBOB:
我曾经使用INI文件或者配置文件保存配置数据,但是每次读取它们非常繁琐,而且每当我需要读取一个仪器的GPIB地址时,速度很慢。如果使用文件,我通常在程序开始时读取文件,然后把配置数据保存在WORM全局变量(写一次,读任意)中,在状态机中使用它们。
--------------------------------------------------------------------------------------------------------------------------
BEN:
周末我又考虑一下全局变量的问题。
WORM GLOBALS(写一次,读多次)----------在你是程序开发者而且只有你是程序开发者的情况下是安全的。
------------------------------------------------------------------------------------------------------------------------------
TBOB:
很现实的想法,BEN.我只有在常量的情况或者WORM GLOBALS时才使用全局变量。技巧就是对于我的继任者,也告诫他们和采用同样的做法。
------------------------------------------------------------------------------------------------------------------------------
TBOB:
------------------------------------------------------------------------------------------------------------------------------
上一篇:labview的深入探索----labview与回调函数
下一篇:labview的深入探索----整型数据类型和内存映射