月度归档: 2007年1月
记录梦境 5
公司要搬家了,所以昨晚梦到了新的办公室。
主要是梦到了两间会议室,装修得非常豪华。会议室的墙壁是流线型的落地玻璃墙,从外面就看到内部的宽敞舒适了。梦里就是比现时美好 :)
我还梦到公司的一块地面没有铺好。于是我开始和水泥,铺地面(不知道为什么要我来做)。一直铺到梦醒。
帧
不知道是我眼花还是微软的 bug。今天用微软拼音2003试图输入“帧”字,可是怎么找都没找到。最后换了输入法才输入进去。
LabVIEW 程序中的线程 4 – 动态连接库函数的线程
四、动态连接库函数的线程
1. CLN 中的线程设置
LabVIEW 可以通过 CLN(Call Library Function Node)节点来掉用动态连接库中的函数,在 Windows 下就是指 .DLL 文件中的函数。用户可以通过 CLN 节点的配置面板来指定被调用函数运行所在的线程。相对于 VI 的线程配置,CLN 的线程选项非常简单,只有两项:界面线程(Run in UI thread)和可重入方式(reentrant)。(新版本 LabVIEW 把这里的 reentrant 改为 Run in any thread 了)
图1:在 CLN 的配置面板上选择函数运行的线程
在 LabVIEW 的程序框图上直接就可以看出一个 CLN 节点是选用的什么线程。如果是在界面线程,则节点颜色是较深的橘红色的;如果是可重入方式的,自节点是比较淡的黄色。
图2:不同颜色表示 CLN 不同的线程设置
2. 如何选择合适的线程
对于在 CLN 中选取何种线程,有一个简单的判断方法。如果你要使用的动态连接库是多线程安全的,就选择可重入方式;否则,动态连接库不是多线程安全的,就选择界面线程方式。
判断一个动态连接库是不是线程安全的,也比较麻烦。如果这个动态连接库文档中没用明确说明它是多线程安全的,那么就要当他是非线性安全的;如果能看到动态连接库的源代码,代码中存在全局变量、静态变量或者代码中看不到有 lock 一类的操作,这个动态连接库也就肯定不是多线程安全的。
选择了可重入方式,LabVIEW 会在最方便的线程内运行动态连接库函数,一般会与调用它的 VI 运行在同一个线程内。因为 LabVIEW 是自动多线程的语言,它也很可能会把动态连接库函数分配一个单独的线程运行。如果程序中存在没有直接或间接先后关系的两个 CLN 节点,LabVIEW 很可能会同时在不同的线程内运行它们所调用的函数,也许是同一函数。对于非多线程安全的动态连接库,这是很危险的操作。很容易引起数据混乱,甚至是程序崩溃。
选择界面线程方式:因为 LabVIEW 只有一个界面线程,所以如果所有的 CLN 设置都是界面线程,那么就可以保证这些 CLN 调用的函数肯定全部都运行在同一线程下,肯定不会被同时调用。对于非多线程安全的动态连接库,这就保证了它的安全。
3. 与 VI 的线程选项相配合
如果你的程序中大量频繁的调用了动态连接库函数,那么效率就是一个非常值得注意的问题了。
我曾经编写过一个在 LabVIEW 中使用 OpenGL 的演示程序(为了演示我们开发的“Import Shared Library 功能”),对 OpenGL 的调用全部是通过 CLN 方式完成的。由于 OpenGL 的全部操作必需在同一线程内完成,我把所有的 CLN 都设置为在界面线程运行的方式。对 VI 的线程选项没有修改,还是默认的选项。结果程序运行极慢,每秒钟只能刷新一帧图像,CPU 占用 100%。但是作为动画每秒至少25帧才能看着比较流畅。
我开始试图用 LabVIEW 的 profile 工具来查找效率低下的 VI,结果居然查找不到。在 Profile Performance and Memory 工具上显示的 CPU 占用时间只有一点点。这个工具竟然显示不出程序中最耗时的操作在哪里,自然我也对如何优化这个程序无从下手了。后来这个演示程序被搁置了一段时间。
直到有一天我从同事给我的提供的一些信息中得到了启发,才突然想通,这些 CPU 全部被消耗在线程切换中了。我们调用 OpenGL 方法是为每个 OpenGL API 函数包装一个 API VI,这些 API VI 非常简单,程序框图就只有一个 CLN 节点,调用相应的 OpenGL 函数。由于每个 VI 都是在默认的执行线程中运行,而 CLN 调用的函数却是在界面线程下运行的。所以每次执行一次这样的 API VI,LabVIEW 都要做两次线程切换,从执行线程切换到界面线程,执行完函数,在切换回执行线程。
线程切换是比较耗时的。我的演示程序刷新一帧要调用大约两千次 OpenGL API VI,总耗时接近一秒。
解决这个问题,要么把所有 API VI 中的 CLN 都改为可重入方式,但编写程序时要保证所有被调用的函数都运行在同一线程内,这比较困难。比较容易实现的是,把程序中对 OpenGL 操作相关的 VI 也全部都设置为在界面线程下运行。我选择的就是后一种方法。改进后的程序,每秒钟画30帧图像也不会占满 CPU。
由此,我也想通了另一个问题。就是我曾经发现调用 Windows API 函数遇到的错误信息丢失的问题。在调用某一 Windows API 函数返回值为0时,表示有错误发生了。这时你可以调用 GetLastErr 和 FormatMessage 得到错误代码和信息。但是我经常遇到的问题是:前一个函数明明返回值为0,但是随后调用的 GetLastErr 函数却无法查到错误代码。
我想这一定是看上去两个函数是先后被 LabVIEW 调用的,但实际上 LabVIEW 在它们之间还要做两次线程切换才行。错误代码就是在线程切换的过程中被丢失了。解决这个问题的办法也是:把调用这三个函数的 CLN 和调用它们的 VI 全部设置为在界面线程下运行就可以了。
相关文章:
LabVIEW 程序中的线程 1 – LabVIEW 是自动多线程语言
LabVIEW 程序中的线程 2 – LabVIEW 的执行系统
LabVIEW 程序中的线程 3 – 线程的优先级
博客版《我和 LabVIEW》
I have a beef with you
Different ways to say “I think so.”
不要怕,不要悔
今天老妈突然打电话来跟我讨论了一下股票,说最近股市形势很好啊。我老家那里算是祖国边疆了,连从来不接触股票的老妈都听说股市不错,可见过去一段时间的股市大涨影响之广,差不多能吸引进股市的人都已经被吸进去了吧?不过按照以往的规律,一般到了这个时候股市也就危险了。
最近看了一本书,叫做《炒股的智慧》。看过之后,非常欣赏作者的观点。当然我算欣赏的不是作者介绍的炒股技术,而是作者对待股票买卖、涨跌的心态。给我印象最深的是两点:
第一:不要怕,不要悔。不仅是炒股,应该说对待人生中各种经历都应当这样。人要勇敢,尤其是年轻的时候,要敢于尝试。不是所有的尝试都会成功,尝试之后不论结果如何,不要后悔自己当初的决定。不去尝试,永远不知道结果如何。
第二:小偷的技术不在于偷,而在于逃;同样,炒股的技术不在于买,而在于卖。钱要落袋为安才算数的。
关于炒股,我有过一次很深的教训。和我有同样经历的人大概不多,因为到目前为止,中国只有一只真正退市股票-达尔曼,就是我当时买的那一只。这只股票最高时价格好像是四五十元的样子,我是在15元时买进的。我当时想这只股票好,已经跌了这么多了,因该不会再跌了。我不是经常关心股票的,等我过了几个月再去查看它的时候,它已经是6元钱一股了。我想,可不能就这么把它卖了,否则就亏大了,不如再等等看。又过了一段时间,它就跌到3元了。等他跌到1元以下的时候,我想:卖了它,也收不回几个钱了,不如留着,也许还有希望。总不至于这只股票变没了吧。结果还是没卖掉它。又过一段时间,我再去查看我的帐户,这只股票真的就不见了。
塞翁失马,焉知非福。如果没有这段经历,我也许还不会下定决心去详细了解股票这东西。
不过意识到自己根本没精力去跟踪股票,我现在已经不再炒股了。目前一般做一些像基金、打新股这类不太需要费心,风险又比较低的投资。
《生活随笔》
快乐的大脚
刚刚在我的电脑上看完了动画片《快乐的大脚》(Happy Feet)。没看之前我还没有听说过这部影片,所以在观看它的时候感觉非常震撼。这是近期非常难得的一部能感动得的影片。强烈推荐给大家。
这部影片有几个非常吸引人的特色:
首先是它引人入胜应该数它的音乐了,音乐是这部影片非常重要的一个元素。影片从头到尾机会没有间断过各种风情的歌曲和音乐。如果他是真人拍摄的就应该被归为音乐剧了。影片中每一首歌曲都很悦耳,不论是原创的还是改变的。我在看完电影之后还把它倒回去欣赏了多次,就是为了听听它的音乐。
影片画面极其精美,影片展现的最多的是南极的壮美景观和可爱的企鹅们。这虽然是一部动画片,但它插入了大量真实拍摄的场景和人物。要不是影片中的企鹅又唱又跳,真的很难看出这是一部动画片。
影片的主题是宣传环保的,这是真正能在情感上感动我的地方。
《生活随笔》
回答一个关于 IVI 仪器驱动程序的问题
今天在我的 blog 上看到了一个关于 IVI 的问题,在这里回答一下。
问题:
“阮先生,你好,我看过你写的关于IVI的文章,写得很详细,有个问题想请教一下,我现在是用LabVIEW的,CVI没有用过,我应该也可以用LabVIEW来开发自己的IVI仪器驱动吧?目前我已经安装了IVI Compliance Package (ICP) 2.5,但是如果要使用自己开发的IVI驱动能出现在MAX上面,是否还需要一些Toolset?比如IVI Installer Creator and the IVI Specific Driver Test Suite之类的?还是我可以用其他什么方法做到.好像那些Toolset不是免费的,我有没有方法可以尽量不用购买什么工具包就可以使用自己的IVI仪器驱动呢?谢谢!
阮先生你好,我是问你IVI问题的那个人,我想到一个方法不知道能不能行得通,如果说我只是使用IVI驱动里某一类驱动程序(比如信号源)很简单的通用属性(比如只是使用到信号源的二个通用属性:频率和功率,全部信号源都支持这二个属性的设置),那我可不可以在NI的网站上下载某一型号信号源的IVI驱动(我手上有另外一种不同型号的信号源,但没有发现我手头上这个信号源的IVI驱动程序),然后安装这个IVI驱动,把其他特有的属性去掉,只留下共用的属性,然后用这个下载的IVI驱动来驱动我手头上这个信号源(假设二种信号源在设置频率和功率时所使用到的命令都是完全相同的,尽管它们的型号是不一样的)?不知道有没有把问题说清楚,还请多多指教.另外,不知道在这里问问题合不合适.谢谢”
回答:
目前不能用 LabVIEW 编写 IVI 仪器驱动程序,只能用 C 语言编写 IVI。LabVIEW IVI 驱动程序是在已有的 C IVI 驱动程序基础上包装一下得来的,不能在没有 C IVI 的时候直接去开发 LabVIEW IVI。
现存的直接使用 LabVIEW 编写仪器驱动程序大多是符合 VXIpnp 标准的仪器驱动程序。如果你用不到互换性,VXIpnp 仪器驱动程序就可以满足要求了。目前,IVI 的可互换性的应用也不是很多,也许你可以考虑直接编写 LabVIEW VXIpnp 仪器驱动程序。
如果要开发 IVI 驱动程序,最好要有最新版的 CVI 和 IVI Compliance Package (ICP)。其它工具包都可以不用。
IVI Spacific Driver 是针对某一型号的仪器专用的 IVI 驱动程序。它是不能被用到其它型号的一起上的,就算是只用到通用属性也不行。原因有两个,一个是每个仪器的命令可能是不同的,另一个是驱动程序在初始化的时候就会检查仪器是不是自己所支持的。如果两个型号的仪器所用的命令完全相同,你也好要改一下 Init 函数的源代码才能把驱动用到另一台仪器上。