windows下 DLL 的学习
2013-10-13 11:34
295 查看
windwos下的 DLL 有copy on write (写入拷贝机制)
如果调用G e t M o d u l e H a n d l e函数,线程就能够确定D L L是否已经被映射到进程的地址空间
HINSTANCE hInstance=GetMoudleHandle("MyLib");
if(!hInstance )
{
HINSTANCE hInstanceDll= LoadLibrary("MyLib.dll");
}
例如,只有当MyLib.dll尚未被映射到进程的地址空间中时,下面这个代码才能加载该文件:
通过GetProcAddress 函数来获取动态链接库中的函数地址
PROCFUN myFun= GetProcAddress(hInstanceDll,"MyFunAdd");
myFun(1,2);
顺序调用DLL
系统是顺序调用D L L的D l l M a i n函数的。为了理解这样做的意义,可以考虑下面这样一个环境。假设一个进程有两个线程,线程A和线程B。该进程还有一个D L L,称为S o m e D L L . d l l,它被映射到了它的地址空间中。两个线程都准备调用C r e a t e T h r e a d函数,以便再创建两个线程,即线程C和线程D。
当线程A调用C r e a t e T h r e a d来创建线程C时,系统调用带有D L L _ T H R E A D _ AT TA C H值的S o m e D L L . d l l的D l l M a i n函数。当线程C执行D l l M a i n函数中的代码时,线程B调用C r e a t e T h r e a d函数来创建线程D。这时系统必须再次调用带有D
L L _ T H R E A D _ AT TA C H值的D l l M a i n函数,这次是让线程D 执行代码。但是,系统是顺序调用D l l M a i n函数的,因此系统会暂停线程D的运行,直到线程C完成对D l l M a i n函数中的代码的处理并且返回为止。
当线程C完成D l l M a i n的处理后,它就开始执行它的线程函数。这时系统唤醒线程D,让它处理D l l M a i n中的代码。当它返回时,线程D开始处理它的线程函数。
通常情况下,根本不会考虑到D l l M a i n的这个顺序操作特性。我曾经遇到过一个人,他的代码中有一个D l l M a i n顺序操作带来的错误。他创建的代码类似下面的样子:
你能够看出这个问题吗?当D l l M a i n收到D L L _ P R O C E S S _ AT TA C H 通知时, 一个新线程就创建了。系统必须用D L L _ T H R E A D _ AT TA C H的值再次调用D l l M a i n函数。但是,新线程被暂停运行,因为导致D L L _ P R O C E S S _ AT TA C H被发送给D l l
M a i n函数的线程尚未完成处理操作。问题是调用Wa i t F o r S i n g l e O b j e c t函数而产生的。这个函数使当前正在运行的线程暂停运行,直到新线程终止运行。但是新线程从未得到机会运行,更不要说终止运行,因为它处于暂停状态,等待当前线程退出D l l M a i n函数。这里我们得到的是个死锁条件。两个线程将永远处于暂停状态。
如果调用G e t M o d u l e H a n d l e函数,线程就能够确定D L L是否已经被映射到进程的地址空间
HINSTANCE hInstance=GetMoudleHandle("MyLib");
if(!hInstance )
{
HINSTANCE hInstanceDll= LoadLibrary("MyLib.dll");
}
例如,只有当MyLib.dll尚未被映射到进程的地址空间中时,下面这个代码才能加载该文件:
通过GetProcAddress 函数来获取动态链接库中的函数地址
PROCFUN myFun= GetProcAddress(hInstanceDll,"MyFunAdd");
myFun(1,2);
顺序调用DLL
系统是顺序调用D L L的D l l M a i n函数的。为了理解这样做的意义,可以考虑下面这样一个环境。假设一个进程有两个线程,线程A和线程B。该进程还有一个D L L,称为S o m e D L L . d l l,它被映射到了它的地址空间中。两个线程都准备调用C r e a t e T h r e a d函数,以便再创建两个线程,即线程C和线程D。
当线程A调用C r e a t e T h r e a d来创建线程C时,系统调用带有D L L _ T H R E A D _ AT TA C H值的S o m e D L L . d l l的D l l M a i n函数。当线程C执行D l l M a i n函数中的代码时,线程B调用C r e a t e T h r e a d函数来创建线程D。这时系统必须再次调用带有D
L L _ T H R E A D _ AT TA C H值的D l l M a i n函数,这次是让线程D 执行代码。但是,系统是顺序调用D l l M a i n函数的,因此系统会暂停线程D的运行,直到线程C完成对D l l M a i n函数中的代码的处理并且返回为止。
当线程C完成D l l M a i n的处理后,它就开始执行它的线程函数。这时系统唤醒线程D,让它处理D l l M a i n中的代码。当它返回时,线程D开始处理它的线程函数。
通常情况下,根本不会考虑到D l l M a i n的这个顺序操作特性。我曾经遇到过一个人,他的代码中有一个D l l M a i n顺序操作带来的错误。他创建的代码类似下面的样子:
BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD fdwReason, PVOID fImpLoad) { HANDLE hThread; DWORD dwThreadId; switch(fdwReason) { case DLL_PROCESS_ATTACH: // The DLL is being mapped into the process's address space. // Create a thread to do some stuff. hThread = CreateThread(NULL, 0, SomeFunction, NULL, 0, &dwThreadId); // Suspend our thread until the new thread terminates. WaitForSingleObject(hThread, INFINITE); // We no longer need access to the new thread. CloseHandle(hThread); break; case DLL_THREAD_ATTACH: // A thread is being created. break; case DLL_THREAD_DETACH: // A thread is exiting cleanly. break; case DLL_PROCESS_DETACH: // The DLL is being unmapped from the process's address space. break; } return(TRUE); }
你能够看出这个问题吗?当D l l M a i n收到D L L _ P R O C E S S _ AT TA C H 通知时, 一个新线程就创建了。系统必须用D L L _ T H R E A D _ AT TA C H的值再次调用D l l M a i n函数。但是,新线程被暂停运行,因为导致D L L _ P R O C E S S _ AT TA C H被发送给D l l
M a i n函数的线程尚未完成处理操作。问题是调用Wa i t F o r S i n g l e O b j e c t函数而产生的。这个函数使当前正在运行的线程暂停运行,直到新线程终止运行。但是新线程从未得到机会运行,更不要说终止运行,因为它处于暂停状态,等待当前线程退出D l l M a i n函数。这里我们得到的是个死锁条件。两个线程将永远处于暂停状态。
相关文章推荐
- poj1562 Oil Deposits
- 【网络】RFC1245-OSPF Protocol Analysis
- UML 依赖 关联 聚合 组合
- 彩色BMP转换成灰度图的原理
- 两种原始数据库读取方法
- 系统调用过程分析
- Expanding Rods(二分)
- P1055 奶牛浴场 - Vijos
- std::map lower_bound,upper_bound的用法举例
- WPF的动画实现方式
- log4j配置详解
- ARM映像文件
- Java技术专题之JVM逻辑内存回收机制研究图解版
- 在农村,老人没什么病,不要为了下一辈的人操心
- SVN1.8.3简单安装及配置
- 错误“Unexpected namespace prefix "xmlns" found for tag LinearLayout”的解决方法
- SigPipe信号
- IE6 png 透明 (三种解决方法)(转来的哦)
- PAT Advanced 1042
- 联系人软件知识点