后台任务

    有一些任务在运行的时候,并不需要与用户交互。它们通常在不打扰用户其它工作的时候默默的执行。这样的任务叫后台任务。与之对比,前台任务就是用户看得见的。
    比如,一个文本编辑软件,帮助用户上编辑文字的任务都是前台执行的。如果这个软件做得好,最好还有自动保存文件的功能,这样在系统突然崩溃之后,不至于所有用户做的改动都白费。自动保存这个功能一般都被作为后台任务,他在执行时,不打扰用户其它工作。
    后台任务的应用还有很多。在 LabVIEW 中实现后台任务的方法,就是使用 VI Scripting 技术,动态把负责后台的任务在新的线程里启动起来。下面以一个比较常用的功能来说明后台任务是如何实现的。

    大型 LabVIEW 程序启动的时候可能会比较慢,这是因为程序在它所有的子VI都被装入内存之后才能执行。把大量子VI装入内存可能要花费几秒钟的时间,如果这段时间,什么都不显示给用户,用户可能会以为是程序出错或者死机了,从而做出一些错误的操作。好的做法是,在启动程序的时候立刻显示给用户一个提示界面,告诉用户程序正在装载,已经装载的进度。同时把所有的子VI装入内存,然后再启动程序的主界面。
    在程序显示启动画面这个阶段,当子VI全部装入内存后,启动画面仍然显示在前台,而程序会再启动一个后台任务,把主程序运行起来。之后,启动画面程序把自己关闭,而主程序界面也从后台跳到前台来了。
    启动画面的程序代码如下图所示:

    它由5个部分组成:
    第1部分负责把主程序的子VI都装入内存(用 Open VI Reference 函数打开这些子 VI 就可以把它们装入内存)。这部分与后台任务无关,不细说了。
    第2部分 Open VI Reference 函数打开主程序的主VI,它的输入是主VI的地址。后续使用到的针对这个 VI 的 Scripting 函数,都依赖于在此打开的 VI 的引用。
    第3部分设置主VI的 Front Panel:Open 属性。这个属性值为真的时候,主程序的界面被显示出来。在我们这个程序中,主程序最终是要跳到前台来与用户交互的,所以需要显示他的界面。有些后台任务,比如自动保存任务,没有交互界面,就不需要设置此属性。
    第4部分调用主VI的 Run VI 方法。调用这个方法之后,主程序开始运行。目前主程序还是作为后台任务在运行。这里需要注意的是 Run VI 方法的两个参数:
    Wait Until Done 参数如果设为真,启动画面程序运行到这里就会暂停下来,一直等到后台任务结束,才继续执行后面的代码。但是,作为启动画面程序,我们显然不希望出现这种情况。我们需要让前台任务和后台任务同时执行,所以这个参数在本程序中被设为“假”。后台程序在另一个线程中被执行,它的结束与否不影响当前程序的执行,我们的启动画面程序会立即去执行下一条语句。
    用 Open VI Reference 函数打开的引用必须被关掉,否则,VI被装入内存,却从来不被卸除出内存,就会引起内存泄漏。Auto Dispose Ref 参数用于决定由谁来关闭动态运行起来的VI的引用,是前台任务,还是后台任务自己。真对于我们的例子,后台任务是主程序,我们希望用户关闭它的同时,把它从内存中卸除。所以实例中这个参数的值是“假”,后台程序结束时自动释放引用。对于那些没有界面的后台任务,它们的启动、停止都需要由前台程序来控制。这是这个参数就需要被设为“真”。前台程序还需要这个引用来停止后台任务、卸除后台任务的VI。
    第5部分是对启动画面VI自身进行操作的。程序运行到这里,主程序已经运行起来,而启动画面程序的使命也已完成,应当让位给主程序了。启动画面程序在此调用 Front Panel:Close 把自己关闭。

《我和 LabVIEW》目录

Advertisements

22 thoughts on “后台任务

  1. 不出现在进程列表恐怕不行。我没做过Windows后台服务,但他肯定需要比一般程序高的权限,LabVIEW不一定能做到。数据交换使用共享变量最方便。

  2. 谢谢!我尝试一下您的方法,不知道数据交互上是否方便。原本我很像实现那种像Windows后台服务那样的程序,不想让它出现在进程列表中。一直没有找到这方面的相关介绍和资料。

  3. 有一个简单的办法,你编写一个没有界面的程序,制作成EXE文件。然后在注册表中把这个程序设置为开机即运行就可以了。

  4. 这两种后台任务的层次不同。Windows中的常驻后台服务程序,是一个独立的程序,可以脱离任何其他程序独自运行。LabVIEW中的后台任务是LabVIEW进程的一部分。它不能脱离LabVIEW或者是LabVIEW生成的应用程序,它只能在这些应用程序中处理界面之外的工作。

  5. 应该这么说,我说的比较简单,只是从使用方法上说了一下两者个区别。LV help解释的比较深入。不过后台程序界面是否打开,与这个参数无关。这个参数主要还是用来确定谁来管理被打开的VI refunm。如果设成false,必须使用Close函数来关闭被打开的VI refnum。如果设成true,那可以不调用VI refnum。当后台程序停止运行,则VI refunm自动关闭。如果后台程序有界面,则一般是关闭界面时,程序结束,VI refunm自动关闭。

  6. 依您的意思,如果我动态打开的是后台程序(不需开界面)就把Auto Dispose Ref 设为true, 如果动态打开的是有界面的程序,就把Auto Dispose Ref 设为false? 那动态打开的程序所要的数据内存空间是按什么方式回收的呢?

  7. Auto Dispose Ref : Allows you to run a VI independently of the caller without opening its front panel immediately or opening another reference inside the target VI. If TRUE, the referenced VI transfers ownership of the reference from the calling VI to the VI that is running. This means LabVIEW disposes of the reference, along with the parallel data space, when the target VI goes idle, not when the VI that opened the reference goes idle. The reference can still be used by the calling VI until the target VI closes the reference. The calling VI does not need to close the reference unless the Run VI method returns an error. If the calling VI does close the reference, the target VI can abort and leave memory. If FALSE, LabVIEW automatically disposes of the VI reference when the VI that opened it goes idle. The default is FALSE. Note If Auto Dispose Ref is TRUE and the method returns an error, LabVIEW does not transfer ownership of the reference to the target VI. LabVIEW will not automatically dispose of the reference when the target VI goes idle.

  8. 小弟补充一点:第4步中wait until done参数为真,一般是在测试系统里面用.把很多测试subvi放在一个文件夹main函数从中调用,这样好处是可以拓展测试程序而不必更改main函数,不过要求所有subvi必须作成一种格式

  9. 我明白了,谢谢阮大侠了,真是好人!
    高杰先生,也谢谢你的回答,我认识你一个朋友:王磊。

  10.     用图中标号2的 Open VI Reference 函数打开一个VI的引用,就可以把这个VI连同他所有的子VI全部装入内存。如果启动画面不需要什么动态的信息,直接打开主VI的引用就行了。如果还需要显示装载的进度,你肯定能就不希望一次装一个主VI进来,而是把几百个子 VI 一个一个装入内存,没装入一个启动画面上的进度条前进一格。可以这样实现:    先得到所有子VI文件的路径。这个过程的策略可以你自己制定,比如你规定所有子VI都放在某一文件夹下,那么遍历这个文件夹,得到他下面所有 VI 文件的路径,使用 Open VI Reference 函数把它们一一打开,没打开一个,更新一下进度条。

  11. 静态调用都是自动加载的。动态调用,嘛玩意要调那么多啊?at least,初始化的VI里面,哪需要那么多啊!动态调用VI,如何调用和被调用多少,好像没什么太大的关系。当然,可能是我没有理解这个朋友的问题,也可能是这个朋友没表述的很清楚。譬如说,你可能想问,有什么方式调用很多子VI,比较省内存之类的。呵呵
    阮虾有点忙,俺越俎代庖一下。说的不对的地方,阮虾来纠偏一哈子。

  12. 啊!
    我的程序也是这样,思路完全一致。虽然我做的程序不是很大。但是很多对仪器仪表的初始化,以及仪器仪表本身的Self-test比较费时。所以程序刚开始运行的时候,一定要做这么一个东西。而且做了这个东西,把自己公司、单位甚至自己的个人的信息放在里面,嘿嘿,感觉还是很正式。后来俺又做了改进,显示公司以及部门的log之后,详细的告诉用户,现在是在对系统的哪一个部分进行初始化。好像在放幻灯片一样,呵呵。不过,说老实话,太花哨了,我反而不喜欢。

  13. 看到这几个函数调用好亲切啊。后来我们几乎所有的Wizard程序几乎都是用的这个思路。

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s