博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Web版PACS开发纪要一:关闭动态库中创建的线程
阅读量:5861 次
发布时间:2019-06-19

本文共 3049 字,大约阅读时间需要 10 分钟。

hot3.png

最近的项目是关于B/S架构下的Web版PACS开发,为了缩短研发周期,采用了该领域主流的两大开源库:DCMTK和CxImage。但是由于项目初期对CxImage开源库的编译问题,导致该开源库在MFC下无法正常运行,因此决定将功能函数在控制台下完成,然后封装成动态链接库(XXX.dll),并加载到MFC工程中。下面是对“急救车上的多种医疗设备数据采集客户端”开发中遇到的问题进行的简略记录,主要分为以下几个部分:

1)问题的背景

2)演示工程构建

3)问题分析

4)解决方案

5)总结

一、问题的背景

由于牵扯到过多的医学方面的专业知识,具体背景就不细说了,简而言之,就是一句话——将控制台下完成的功能函数封装成动态库来应用到MFC工程中,完成期望的功能。

二、演示工程构建

 原始的项目中运用了DCMTK和CxImage开源库中的大量的函数,来实现医学图像的解析和传送。如果直接以原工程作为演示工程,过于繁琐,各个库不能独立运行给阅读者带来不便。因此下面搭建了一个简单的测试工程。该工程分为两部分:

1)功能实现部分:FoldWatch20130525,其实现的主要功能与原工程类似(只是省略了对医学图像处理的部分),即监控配置文件foldwatch.ini中给定的源文件夹([Directory]节中指定的值),将其下的所有bmp图像转存到目标文件夹中([DestinationDirectory]节中指定的值)。演示工程中利用了完成端口实现该功能
【注】:该转移bmp文件的功能是可以直接添加到2)中的基于MFC对话框的工程中的,此处为了演示开发项目中遇到的问题,模拟DCMTK+CxImage开源库的状态,假定该功能不能在MFC工程下直接运行,需要将其编译成动态库形式方可。

2)调用显示部分:FoldWatchMain,一个简单的基于对话框的MFC工程。通过按钮来调用1)中创建的功能动态库。

三、问题分析

演示工程的对话框界面如下左图所示:

单击“开始监测”按钮,进入到响应函数中加载动态库中,并调用FoldWatch函数。随后界面处于未响应状态(如上图右)。如果工程出现这种情况,必然会影响到用户体验(在医疗领域就不单单是影响用户体验这么简单了,时间就是生命!!!!!)

【分析原因】发现在文件转移工程动态库中,有一个循环等待的过程while(1);其目的就是为了能够实时持续的监控源文件夹。那么是否可以在主体工程中创建一个线程,然后让该线程调用动态库中的功能函数来实现文件夹的监控,待需要停止时,直接关闭主体进程中的工作线程就可以了。于是进行了以下尝试:

四、解决方案

【尝试一】

在“开始监测”按钮响应函数中利用CreateThread创建一个工作线程,然后调用dll中的工作函数FoldWatch。修改代码如下(完整的工程代码见博文后的链接1):

hInst=LoadLibrary(_T("FoldWatcher20130525.dll"));	if(hInst)	{		typedef int (*pFunc)();		pFunc fun=NULL;		fun=(pFunc)GetProcAddress(hInst,_T("FoldWatch"));		if(fun)		{			//直接调用动态库中的函数			//(*fun)();			//进行工作线程创建,然后在线程中调用动态库的函数			hThread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)fun,NULL,0,NULL);		}	}

如此,创建线程后直接将控制权返回给MFC对话框,解决了对话框无响应的问题。且能够顺利的完成文件夹监控任务。但是无意间又发现了一个问题:单击“停止监测”后,依然能够实现bmp文件转移,难道文件夹监控线程并未停止?为了进一步确认监控线程是否停止,利用微软提供的ProcessExplorer工具来进行观察。

首先运行MFC对话框主程序,可以在ProcessExplorer中看到FoldWatcherMain.exe应用程序。

单击“开始监测”后,加载了功能动态库FoldWatcher20130525.dll,如下图深色条纹所示:

在ProcessExplorer工具的进程窗口(Process)中,单击打开FoldWatcherMain.exe应用程序,选择Thread选项卡,可以看到当先运行的线程

TID=6260,是调用动态库函数的线程;TID=5656的是MFC主线程;TID=5944的是动态库函数中创建的监控文件夹的线程,该线程与完成端口绑定。手动向监控的文件夹中拷贝bmp文件,可以看到5944线程开始运行,CPU利用提高,证明正在转移bmp文件。

单击“停止监测”后,看到TID=6260的动态库调用线程关闭。

但是文件夹监控子线程TID=5944依然存在。

【分析原因】:在MFC主进程中加载了功能动态库,然后创建了一个工作线程调用动态库中的函数,然而该库函数中又创建了一个子线程。该子线程与MFC中创建的线程是否有关系?是否是父子关系?是否关闭了MFC中的工作线程,库函数创建的子线程也同样会关闭呢?答案是否定的。一旦工作线程中创建完成“子线程”后,两者就没有直接的关联关系了,也就是说该“子线程”不隶属于工作线程。因此上面的尝试结果失败的。那么是否有方法来关闭工作线程中创建的“子线程”呢?

【尝试二】

既然工作线程是调用的动态库中的函数,“子线程”是利用动态库函数来创建的,那么是否卸载了动态库,该线程就会停止呢?经过测试,发现卸载动态库后,由动态库创建的“子线程”并未关闭。

【尝试三】

将动态库中创建的线程句柄导出,然后在MFC对话框程序中进行关闭。由于句柄属于内核对象,本人涉猎有限,未找到导出句柄的有效方法,此尝试失败。

【尝试四】

再次分析原本的动态库,发现问题主要出在文件夹监控函数WatchDirectory中存在while(1);语句,导致程序无法退出。那么是否可以将动态库的函数进行重新构造,增加StartWatch()、StopWatch()函数来控制线程的运行和关闭呢?答案是肯定的。(具体的修改代码见博文后的链接2)此时单击“开始监测”,程序运行正常,依然能够实时监控文件夹,转移bmp文件。ProcessExplorer中的观察结果如下:

当单击“停止监测”按钮后,工作线程终止,结果图如下:

至此完成了将文件夹监控功能动态库添加到基于MFC对话框的工程中的任务。 

五、总结:

整个问题的解决耗费了近一天的时间,究其原因主要有两个

1)对问题的“病灶”诊断不清,犹如解决方案中的尝试一所示,并未发现问题的根本在于功能动态库中存在着while(1);这样的阻塞函数,简单的通过工作线程并不能解决while(1);带来的阻塞;

2)对动态库与线程的关系、动态库导出函数和变量,以及线程之间传递句柄基础知识掌握不牢固,尝试二和尝试三浪费了不少时间,无功而返。对此有待进一步的补充学习,希望后期能够将尝试二、尝试三顺利完成,使其达到同样的目的。

尝试一的工程代码:

尝试四的工程代码:

Author:zssure

Date    :2013-05-25

E-mail :zssure@163.com

转载于:https://my.oschina.net/zssure/blog/354764

你可能感兴趣的文章
SuSE Linux上搭建apache+php+mysql环境
查看>>
折腾VMWare Workstation 9在虚拟机中安装Hyper-V服务器
查看>>
SQL Server 2012新增和改动DMV
查看>>
九款即时通讯软件大盘点
查看>>
SQL Server2005数据同步
查看>>
在苹果MAC OS X Lion系统上访问Windows共享文件夹
查看>>
sudo授权的配置以及bash编程之数组和关联数组。
查看>>
[Unity3d]Shader 着色器 学习前了解知识
查看>>
python模块:smtplib模块
查看>>
某商场内无线配置方案
查看>>
XQuery:连通SQL与NoSQL的良好桥梁
查看>>
对话深度学习大神Yoshua Bengio:蒙特利尔何以成为AI圣地?
查看>>
XNA游戏:横竖屏设置
查看>>
机房日常技术总结——Windows篇
查看>>
关于PostgreSQL的GiST索引之一
查看>>
JAVA基础知识(三)
查看>>
如何快速构建高可用集群(Keepalived+Haproxy+Nginx)
查看>>
How to:使用EFS对远程文件服务器上的文件加密
查看>>
Microsoft BitLocker Administration and Monitoring安装
查看>>
前端学习 -- Css -- overflow
查看>>