如何使用 VI 的重入属性

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

2016年04月

在VI Properties -> Execution 中可以选择VI 的Reentrant Execution属性(中文译为:可重入执行)。我们在《LabVIEW 程序的内存优化》一文中讨论过,尽量不要把VI 设置为重入属性,因为这样就多占用了内存,降低了运行效率。此外,如果不加注意的话,还可能引发多线程不安全的问题。尽管可重入VI 在LabVIEW 中不是必须的,但是在某些情况下使用可重入VI 可以简化我们的程序。那么在什么情况下可以使用Reentrant VI 呢?

首先看一下图1 所示的程序,程序中调用的两个子VI 是同一个VI,并且不是可重入的VI。LabVIEW 是自动多线程的语言,那么图中的两个子VI会不会同时执行呢。一定不会的。如果程序中调用的是两个不同的子VI,LabVIEW 有可能会同时在不同的线程执行它们,但对于两次调用相同的子VI,LabVIEW 一定要等一个执行完,再执行另一个。

图1:并行的两个相同子VI

其原因是,LabVIEW 会为每个VI 都开辟一块内存用于数据存储。作为子VI,每次被调用,它的局部变量的数据都是被存在同一地址的。与C 语言相对照,在默认情况下,VI 是不可重入的,VI 中所有的局部变量都是静态变量。如果LabVIEW 在不同的线程下执行同一VI,那么两个线程就会同时对这一块数据地址进行读写,就会导致这一块地址内数据的混乱。为避免此类不安全情况的出现,LabVIEW 必须等待一个子VI 执行结束,再执行另一个子VI。

如果需要图1 中的两个子VI 同时运行,比如子VI 所做的工作是读取文件这样一类耗时多、但CPU占用不大的操作,则并行执行可以大大提高效率。这时,就需要把子VI 设置为可重入了。LabVIEW 在不同的地方调用一个可重入VI 时,会给它另外分配一个独立的数据地址空间。这样就做到了线程安全。在两个线程执行的子VI 使用两份在不同的地址存储的数据,也就不会造成混乱。但是千万要注意,这个“在不同的地方”调用:不可重入的VI 的局部变量与C 语言中非静态变量的含义是不同的。在后面提到的计数器的例子可以验证这一点。

我觉得我说得挺清楚了,出道题目给大家测试一下:

图2:延时子VI

图3:计算延时的主VI

图2 是一个子VI 的代码,功能是延时1000 毫秒。图3 是主VI 的代码,并行调用同一子VI 两次,并计算程序的执行时间。运行主VI,total time 的值是多少?

答案在文章最后。

这是可重入VI 的一种用途,即希望在不同的线程里同时执行同一个子VI。

另外还有一种情况下,也可以用到可重入VI:即需要使用到子VI 中局部变量保存的数据,而在不同的调用处,这些数据是独立不同的。这句话可能解释得不那么清楚,看下面例子就会比较容易理解些。

图4:计数子VI

图5:测试计数的主VI

图4 是一个可重入子VI 的代码,功能是计算这个VI被运行的次数,每运行一次,输出的count 值就增加1。图5 是调用它的主VI,用于演示这个计数器。执行主VI一次,output 1 和output 2 的值分别是10 和20,表示这个子VI 在两处分别被调用了10 次和20 次。

如果把图4 中的VI 改为不可重入,则output 1 和output 2 的输出值是不确定的。大家可以自己试一试,再想一下原因。

当使用递归结构时,参与了递归调用的VI 是需要被同时调用多次的。因此这些VI 中的变量必须是局部的,也就是说参与了递归调用的VI 必须都被设置为可重入。参考:在LabVIEW 中实现VI 的递归调用

测试题目答案:如果图2的子VI 没有设置为可重入,则total time = 2000;如果设置为可重入则total time = 1000。

相关文档
最新文档