DLL(动态链接库)文件是Dynamic Link Library的缩写形式,是一种允许程序共享执行特殊任务所必需的代码和其他资源的可执行文件。其多数情况下是带有DLL扩展名的文件,但也可能是EXE或其他扩展名。Windows提供的DLL文件中包含了允许基于Windows的程序在Windows环境下操作的许多函数和资源。动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。这些函数的可执行代码位于一个DLL中,该DLL包含一个或多个已被编译、链接并与使用它们的进程分开存储的函数。DLL还有助于共享数据和资源,多个应用程序可同时访问内存中单DLL副本的内容。总之,DLL是一个包含可由多个程序同时使用的代码和数据的库。动态链接是相对于静态链接而言的。所谓静态链接是指把要调用的函数或者过程链接到可执行文件中,成为可执行文件的一部分。换句话说,函数和过程的代码就在程序的exe文件中,该文件包含了运行时所需的全部代码。当多个程序都调用相同函数时,内存中就会存在这个函数的多个拷贝,这样就浪费了宝贵的内存资源。而动态链接所调用的函数代码并没有被拷贝到应用程序的可执行文件中去,而是仅仅在其中加入了所调用函数的描述信息(往往是一些重定位信息)。仅当应用程序被装入内存开始运行时,在Windows的管理下,才在应用程序与相应的DLL之间建立链接关系。当要执行所调用DLL中的函数时,根据链接产生的重定位信息,Windows才转去执行DLL中相应的函数代码。
LabVIEW 中是通过Call Library Function Node(CLN)节点来完成DLL文件调用的。创建一个新的VI,右击程序框图,在Functions Palette中依次选中Connectivity——Libraries&Executables工具栏即可找到该节点(图1)。
LabVIEW与外部程序间DLL文件的调用
将节点放置在程序框图中,双击会出现它的配置对话框,共有四页。第一页用于填写被调用函数的信息(图2)。Library name or path需给出DLL文件名和路径,操作系统路径下的DLL文件,直接输入文件名也可调用,否则必须输入全路径。在这里已经给出名字的DLL是被静态加载到程序中的,也就是说当调用了这个DLL的VI被装入内存时,DLL同时被装入内存。LabVIEW也可动态加载DLL,只要勾选上Specify path on diagram的选项即可。选择了这个选项,在 Library name or path中输入的内容就无效了,取而代之的是CLN 节点多出一对输入输出,用于指明所需要使用的DLL的路径。这样,当VI被打开时,DLL不会被装入内存,只用程序运行到需要使用这个DLL中的函数时,才把其装入内存。Function name是需要调用的函数的名称,LabVIEW会把DLL中所有的暴露出来的函数都列出,用户只要在下拉框中选取即可。Thread栏用于设定哪个线程里运行被调用的函数。用户可以通过 CLN 节点的配置面板来指定被调用函数运行所在的线程。CLN 的线程选项非常简单,只有两项: Run in UI thread和Run in any thread。LabVIEW的程序框图上直接可以看出一个 CLN节点是选用
图2 填写被调用函数信息的什么线程。如果Run in UI thread,节点颜色是橙色的;Run in any thread则是浅黄色的(图3)。
图3 CLN不同线程对比
通常情况下,除非使用的动态链接库是多线程安全的,CLN 中选择Run in any thread方式;否则必须选择Run in UI thread方式。判断一个动态链接库是不是多线程安全的,需通过以下方法:如果一个动态链接库的文档中没有明确说明它是多线程安全的,那么就要当作是非多线程安全的;在可以看到动态链接库源代码的条件下,如果代码中存在全局变量、静态变量或者代码中看不到有lock一类的操作,那么这个动态链接库也就肯定不是多线程安全的。
选择了Run in any thread方式,LabVIEW会在最方便的线程内运行动态链接库函数,且一般会与调用它的VI在同一个线程内运行。因为LabVIEW是自动多线程的语言,它也很可能会把动态链接库函数分配给一个单独的线程运行。如果程序中存在没有直接或间接先后关系的两个CLN节点,LabVIEW很可能会同时在不同的线程内运行它们所调用的函数,也许是同一函数。对于非多线程安全的动态链接库,这是很危险的操作。很容易引起数据混乱,甚至是程序崩溃。
选择Run in UI thread方式,因为LabVIEW只有一个界面线程,所以如果所有的CLN设置都是界面线程,那么就可以保证这些CLN调用的函数肯定全部都运行在同一线程下,肯定不会被同时调用。对于非多线程安全的动态链接库,这种方式就保证了它的安全。