关于dll里全局变量的构造和析构的问题, 程序退出时(main return), 到DLL的全局变量析构之间, 主要执行了些什么操作??

xzhangjie 2005-01-07 10:55:27
我在一个DLL里有一个全局的变量, 这个变量的构造函数做一些初始化的操作, 析构函数做一些清理的工作. 但是有一个奇怪的问题, 如果我把这个不做成DLL而是LIB的话, 程序运行是很正常的.
但是我做成DLL后, 析构函数的某操作却死锁了, 调用程序无法退出.而我如果在DLL导出一个函数, 来做那个析构函数做的事情, 然后在调用程序最后调用, 则可以正常退出. 为什么会这样呢?
我是想问, 程序退出时(main return), 到DLL的全局变量析构之间, 到底可能是什么操作, 使我的那些清理操作无法正常执行???
为什么我早些执行就不会出现问题呢?
...全文
375 2 打赏 收藏 转发到动态 举报
写回复
用AI写文章
2 条回复
切换为时间正序
请发表友善的回复…
发表回复
uoyevoli 2005-01-10
  • 打赏
  • 举报
回复
Dll可能被多个进程加载,会不会是这里的问题??
JOSENHUANG 2005-01-10
  • 打赏
  • 举报
回复
copy 一段给你:

在D l l M a i n函数中,我假设你使用M i c r o s o f t的Visual C++编译器来创建你的D L L。
当编写一个D L L时,你需要得到C / C + +运行期库的某些初始帮助。例如,如果你创建的D L L包
含一个全局变量,而这个全局变量是个C + +类的实例。在你顺利地在D l l M a i n函数中使用这个
全局变量之前,该变量必须调用它的构造函数。这是由C / C + +运行期库的D L L启动代码来完成
的。
当你链接你的D L L时,链接程序将D L L的进入点函数嵌入产生的D L L文件映像。可以使用
链接程序的/ E N T RY开关来设定该函数的地址。按照默认设置,当使用M i c r o s o f t的链接程序并
488计计第四部分动态链接库
下载
且设定/ D L L开关时,链接程序假设进入点函数称为_ D l l M a i n C RT S t a r t u p。该函数包含在C / C + +
运行期的库文件中,并且在你链接D L L时它被静态链接到你的D L L文件的映像中(即使你使用
D L L版本的C / C + +运行期库,该函数也是静态链接的)。
当你的D L L文件映像被映射到进程的地址空间中时,系统实际上是调用_ D l l M a i n C RT
S t a r t u p函数,而不是调用D l l M a i n函数。_ D l l M a i n C RT S t a r t u p函数负责对C / C + +运行期库进行初
始化,并且确保在_ D l l M a i n C RT S t a r t u p收到D L L _ P R O C E S S _ AT TA C H通知时创建任何全局或
静态C + +对象。当执行任何C / C + +运行期初始化时, _ D l l M a i n C RT S t a r t u p函数将调用你的
D l l M a i n函数。
当D L L收到D L L _ P R O C E S S _ D E TA C H通知时,系统再次调用_ D l l M a i n C RT S t a r t u p函数。这
次该函数调用你的D l l M a i n函数,当D l l M a i n返回时,_ D l l M a i n C RT S t a r t u p就为D L L中的任何全
局或静态C + +对象调用析构函数。当_ D l l M a i n C RT S t a r t u p收到D L L _ T H R E A D _ AT TA C H通知时,
_ D l l M a i n C RT S t a r t u p函数并不执行任何特殊的处理操作。但是对于D L L _ T H R E A D _ D E TA C H来
说,C / C + +运行期将释放线程的t i d d a t a内存块(如果存在这样的内存块的话)。但是,通常情况
下,这个t i d d a t a 内存块是不应该存在的,因为编写正确的线程函数将返回到内部调用
_ e n d t h r e a d e x的C / C + +运行期的_ t h r e a d s t a r t e x函数(第6章已经介绍),它负责在线程试图调用
E x i t T h r e a d之前释放内存块。
然而,让我们看一看这样一种情况,即用P a s c a l编写的应用程序调用D L L中用C / C + +编写
的函数。在这种情况下, P a s c a l应用程序创建了一个线程,并且不使用_ b e g i n t h r e a d e x。因此线
程对C / C + +运行期库的情况一无所知。这时线程调用D L L中的一个函数,该函数又调用一个C
运行期函数。当你再次调用该函数时, C运行期函数为该线程创建一个t i d d a t a内存块,并且在
创建过程中将它与线程关联起来。这意味着P a s c a l应用程序能够创建成功地调用C运行期函数
的线程。当用P a s c a l编写的线程函数返回时, E x i t T h r e a d被调用。C / C + +运行期库的D L L收到
D L L _ T H R E A D _ D E TA C H通知,并释放t i d d a t a内存块,这样就不会出现任何内存泄漏。这确实
是个非常出色的思路。

15,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧