关于dllmain中的创建新线程,然后...导致死锁

borz 2001-12-14 04:12:00
//dll name "dll2.dll"
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
HANDLE hThread;
DWORD ThreadId;
switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
//DisableThreadLibraryCalls((HINSTANCE)hModule);
hThread = CreateThread(NULL,0,ThreadProcFun,NULL,0,&ThreadId);
WaitForSingleObject(hThread,INFINITE);
CloseHandle(hThread);
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}


在另一main cpp中
#include <windows.h>
#include <stdio.h>
typedef int(*PFUN_fnDll1)(void);
void main()
{
HINSTANCE hInstDll;
PFUN_fnDll1 pFun;
LPCSTR dllfile = "dll2.dll";

hInstDll = LoadLibrary(dllfile); //执行到这里时出现死锁
}

烦请各位给个死锁的理由
...全文
551 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
borz 2001-12-14
  • 打赏
  • 举报
回复
我的qq:57226475
borz 2001-12-14
  • 打赏
  • 举报
回复
谢谢 caigzhi,一语中的,能交个朋友吗?
给分了,
caigzhi 2001-12-14
  • 打赏
  • 举报
回复
新线程在DLL_PROCESS_ATTACH结束前不会跑的起来,那时还没有新线程的入口地址和执行代码
dgb 2001-12-14
  • 打赏
  • 举报
回复
han012(阿毛) 说的很好 Cannot Create an MFC Thread During DLL Startup
borz 2001-12-14
  • 打赏
  • 举报
回复
可我认为在DisableThreadLibraryCalls()之后,DLL_PROCESS_ATTACH能走完啊(线程
ThreadProcFun可以走完,WaitForSingleObject也可以走完,然后CloseHandle(),然后break; 难道有错吗?

--请恕小弟愚笨
caigzhi 2001-12-14
  • 打赏
  • 举报
回复
如果没有,建议一定买一本(最好是它的第四版(Windows核心编程)),
这是windows用户态编程最好的书
caigzhi 2001-12-14
  • 打赏
  • 举报
回复
你理解错了,只有DLL_PROCESS_ATTACH完成以后系统才能使用导入DLL的地址空间,这是常规方法不可逾越的步骤。
borz 2001-12-14
  • 打赏
  • 举报
回复
小弟一时半 找不到那本书啊
borz 2001-12-14
  • 打赏
  • 举报
回复
一时半晌找不到这本书啊
caigzhi 2001-12-14
  • 打赏
  • 举报
回复
《Windows高级编程指南》P433-434里有一样的例子和说明
borz 2001-12-14
  • 打赏
  • 举报
回复
小弟不明白,为什么不会再次有调用dllmain的企图了而还是会
"系统根本到不WaitForSingleObject的后一句指" ?,我的理解是ThreadProcFun,
很快就会执行完毕,而WaitForSingleObject也会执行成功并且反回

请"caigzhi"继续指点
caigzhi 2001-12-14
  • 打赏
  • 举报
回复
就算如此,系统必须在执行从DllMain的DLL_PROCESS_ATTACH完成后才会继续Dll的操作,
刚刚说的DLL_THREAD_ATTACH只是代表DLL_PROCESS_ATTACH的后续动作而已,
也就是系统根本到不WaitForSingleObject的后一句指令,所以也不会对Dll继续执行
cmpp 2001-12-14
  • 打赏
  • 举报
回复
我来学习一下!
hdj0569 2001-12-14
  • 打赏
  • 举报
回复
把WaitForSingleObject先注掉,不处理同步。

试一试。
han012 2001-12-14
  • 打赏
  • 举报
回复
DllMain()中不能创建线程!

PRB: Cannot Create an MFC Thread During DLL Startup

SYMPTOMS
An MFC DLL that creates a new MFC thread during startup hangs when loaded by an application. This includes whenever a thread is created by calling AfxBeginThread or CWinThread::CreateThread inside:

the InitInstance of a CWinApp-derived object in a Regular DLL.
a supplied DllMain or RawDllMain function in a Regular DLL.
a supplied DllMain or RawDllMain function in an Extension DLL.

CAUSE
For Regular DLLs, which have a CWinApp-derived object, the CWinApp::InitInstance override is called from MFC's supplied DllMain when a process is attaching to the DLL. That is, DllMain is entered with a Reason For Call of DLL_PROCESS_ATTACH, and in handling this, MFC calls in to InitInstance before cleaning up and leaving DllMain.

For Extension DLLs, the startup of the DLL is the same, except Extension DLLs do not have a CWinApp-derived object and therefore have no InitInstance.

Whenever new threads are created that use code in the DLL, DllMain is called with a Reason For Call of DLL_THREAD_ATTACH to announce to the DLL that a new thread is attaching to it. If a new thread is created in the InitInstance of an MFC Regular DLL or in the DllMain of any MFC DLL during DLL_PROCESS_ATTACH, this second thread will attempt to re-enter the DllMain, which has not yet been exited from in an effort to announce DLL_THREAD_ATTACH.

DllMain, however, is not re-entrant. That means that the second thread will not start executing until the initial creating thread has finished its work in InitInstance, returned to and left DllMain.

In versions of MFC included with 32-bit Visual C++ versions 2.2 and earlier, MFC allowed threads to be created during startup, and usually DLLs that did this would work acceptably. The second thread would get created without problem but would not start executing until the first thread left DllMain. However, it has never been a good idea to create threads in DllMain during DLL_PROCESS_ATTACH.

As of MFC 4.0, the CWinThread::CreateThread function, which is called by AfxBeginThread, now waits on the created thread to start up and initialize MFC specific data before it returns control to the calling thread. Because the second thread is waiting on the first thread to leave DllMain, both threads crash headlong into deadlock and the application hangs.

Note that this information is equally valid for the RawDllMain function. Moreover, MFC DLLs should not use a RawDllMain function at all.

RESOLUTION
Regular DLLs that create threads should only do so in functions exported from the DLL and called by client applications. Furthermore, no MFC DLL -- neither Extension nor Regular -- should create an MFC thread in the DllMain or RawDllMain function. This ensures that the thread will not be created in the middle of any critical startup code.

The recommended solution for MFC DLLs that need to create a thread when the DLL starts is to add a specific exported initialization function and create the thread in it. Applications that use the DLL would need to call this function sometime during startup, most likely during the application's InitInstance if it uses MFC. Or, if the application is loading the DLL explicitly, the application should call the initialization function immediately after the call to load the library.

The practice of exporting an initialization function for a DLL is not uncommon. Nevertheless, there may be situations where DLLs created with earlier versions of MFC are being ported but the client application cannot be changed to include a call to an initialization function. The alternative to an initialization function is to create the thread in one of the pre- existing exported functions. Any of the DLL's exported functions that require a running thread should be responsible for first checking to see if that thread exists and then creating it if it does not.

STATUS
This behavior is by design.


borz 2001-12-14
  • 打赏
  • 举报
回复
那我如果
DisableThreadLibraryCalls((HINSTANCE)hModule);
强制线程创建时不用DLL_THREAD_ATTACH来调用dllmain呢? 我试了,还是会死锁
caigzhi 2001-12-14
  • 打赏
  • 举报
回复
很简单:
系统要再用DLL_THREAD_ATTACH来调用Dll,之后线程才真正启动,
但是系统在DLL_PROCESS_ATTACH时就WaitForSingleObject(),
所以永远都没机会用DLL_THREAD_ATTACH,而线程也不会得到执行并退出,
所以也没机会通过WaitForSingleObject,因此死锁了
borz 2001-12-14
  • 打赏
  • 举报
回复
DWORD WINAPI ThreadProcFun(LPVOID lpPar)
{
printf("Hello ! I'm in ThreadProcFun(..),that created by DllMain()'s section:DLL_PROCESS_ATTACH\n");
return 1;
}
xiaoxiaohan 2001-12-14
  • 打赏
  • 举报
回复
不用CreateThread,换成beginthreadex吧。
threads 2001-12-14
  • 打赏
  • 举报
回复
ThreadProcFun也帖出来吧
第一部分 概 述 第1章 调试工具简介 1 1.1.泄漏诊断工具 1 1.2.Windows调试工具集 3 1.3.UMDH 4 1.4.Microsoft.应用程序验证器 4 1.5.全局标志 9 1.6.进程浏览器11 1.7.Windows驱动程序开发包 12 1.8.Wireshark 14 1.9.DebugDiag 15 1.10.小结 15 第2章.调试器简介 16 2.1.调试器的基础知识 16 2.1.1.调试器类型 17 2.1.2.调试器命令 18 2.1.3.调试器的配置19 2.1.4.通过内核态调试器重定向用户 态调试器 24 2.1.5.是否使用KD 26 2.2.基本的调试任务26 2.2.1.键入调试命令27 2.2.2.解析调试器的提示信息27 2.2.3.配置和使用符号 29 2.2.4.使用源文件 38 2.2.5.分析命令40 2.2.6.修改上下文的命令60 2.2.7.其他的辅助命令 67 2.2.8.示例68 2.3.远程调试 70 2.3.1.Remote.exe 70 2.3.2.调试服务器 71 2.3.3.进程服务器与内核服务器 73 2.3.4.远程调试的符号解析74 2.3.5.远程调试的源代码解析 75 2.4.调试场景 75 2.4.1.调试非交互式进程(服务 或者COM服务器) 76 2.4.2.在没有内核态调试器的情况 下调试非交互式进程(服务 或者COM服务器) 77 2.5.小结 77 第3章.调试器揭密 78 3.1.用户态调试器的内幕78 3.1.1.操作系统对用户态调试器的支持78 3.1.2.调试事件的顺序 83 3.1.3.控制来自调试器的异常和事件 84 3.1.4.内核态调试器的调试事件处理105 3.2.控制调试目标 106 3.2.1.断点的工作原理 107 3.2.2.内存访问断点的工作原理 108 3.2.3.处理器跟踪 109 3.2.4.实时调试线程状态管理109 3.2.5.通过用户态调试器来挂起线程 112 3.3.小结 113 第4章.符号文件与源文件的管理 114 4.1.调试符号的管理114 4.1.1.公有符号的生成 115 4.1.2.在符号库存储符号 117 4.1.3.在HTTP服务器上共享公有符号 119 4.2.源文件的管理 120 4.2.1.收集源文件信息 120 4.2.2.源文件信息的使用122 4.2.3.不带源文件修订控制的源文件 服务器 123 4.3.小结 125 第二部分.调 试 实 践 第5章.内存破坏之一—栈 127 5.1.内存破坏的检测过程128 5.1.1.步骤1:状态分析 128 5.1.2.步骤2:源代码分析 129 5.1.3.步骤3:使用内存破坏检测工具 133 5.1.4.步骤4:调整源代码 133 5.1.5.步骤5:定义回避策略 133 5.2.栈内存破坏133 5.2.1.栈溢出 142 5.2.2.异步操作与栈顶指针 147 5.2.3.调用约定的不匹配154 5.2.4.回避策略164 5.3.小结 166 第6章.内存破坏之二—堆 167 6.1.堆简介167 6.1.1.前端分配器 168 6.1.2.后端分配器 169 6.2.堆破坏181 6.2.1.使用未初始化状态181 6.2.2.堆的上溢与下溢 185 6.2.3.堆句柄的不匹配 195 6.2.4.重用已删除的堆块199 6.3.小结 205 第7章.安全 206 7.1.Windows安全概述 206 7.1.1.安全标识符 207 7.1.2.访问控制列表208 7.1.3.安全描述符 209 7.1.4.访问令牌211 7.2.安全信息的来源213 7.2.1.访问令牌213 7.2.2.安全描述符 215 7.3.如何执行安全检查 217 7.4.在客户端/服务器程序传播标识 218 7.4.1.远程认证与安全支持提供者接口218 7.4.2.模拟级别220 7.5.系统边界上的安全检查 220 7.6.安全故障的分析221 7.6.1.本地安全故障221 7.6.2.延迟初始化的安全问题 226 7.6.3.身份模拟的潜在安全问题 231 7.6.4.分布式COM错误 232 7.6.5.扩展命令!token的故障241 7.6.6.在Windows XP SP2上安装了 某个程序后发生DCOM激活故障243 7.6.7.通过跟踪工具来分析安全故障 247 7.7.小结 248 第8章.进程间通信 249 8.1.通信机制 249 8.2.本地通信分析 250 8.2.1.LPC的背景知识 251 8.2.2.调试LPC通信251 8.2.3.调试本地DCOM以及MSRPC通信 254 8.3.远程通信分析 260 8.3.1.RPC故障测定状态信息的使用 260 8.3.2.网络流量分析270 8.3.3.打破调用路径275 8.4.一些其他的技术信息277 8.4.1.远程认证277 8.4.2.RPC扩展错误信息 278 8.4.3.其他工具278 8.5.小结 279 第9章.资源泄漏 280 9.1.什么是资源泄漏280 9.2.高层流程 280 9.2.1.步骤1:找出潜在的资源泄漏 281 9.2.2.步骤2:什么东西正在泄漏 282 9.2.3.步骤3:初步分析 282 9.2.4.步骤4:资源泄漏检测工具 282 9.2.5.步骤5:制定回避策略 283 9.3.资源泄漏的可重现性283 9.4.句柄泄漏 284 9.4.1.存在泄漏的程序 285 9.4.2.步骤1和步骤2:它是不是一个 句柄泄漏 286 9.4.3.步骤3:初始分析 287 9.4.4.更复杂的程序290 9.4.5.步骤4:利用泄漏检测工具 292 9.4.6.句柄注入与!htrace 298 9.4.7.步骤5:为句柄泄漏制定回避策略 300 9.5.内存泄漏 301 9.5.1.一个简单的内存泄漏 301 9.5.2.步骤1和步骤2:是否存在泄漏, 以及泄漏的是什么资源 302 9.5.3.步骤3:使用内存检测工具 303 9.5.4.步骤4:回避策略 322 9.6.小结 322 第10章.同步 323 10.1.同步的基础知识 323 10.1.1.事件 323 10.1.2.临界区 325 10.1.3.互斥体 329 10.1.4.信号量 330 10.2.高层流程 331 10.2.1.步骤1:识别问题的征兆 331 10.2.2.步骤2:转储所有线程331 10.2.3.步骤3:分析线程的同步问题332 10.2.4.步骤4:修复问题334 10.2.5.步骤5:制定回避策略334 10.3.同步情况 334 10.3.1.死锁 334 10.3.2.第1种孤立临界区情况—异常 338 10.3.3.第2种孤立临界区情况—线程 结束 343 10.3.4.DllMain函数的注意事项 347 10.3.5.锁竞争 353 10.3.6.管理临界区 358 10.4.小结 361 第三部分.高 级 主 题 第11章.编写定制的调试扩展363 11.1.调试扩展简介 363 11.2.调试扩展示例 365 11.2.1.调试扩展模型 369 11.2.2.调试扩展示例的需求 371 11.2.3.头文件和代码组织 372 11.2.4.调试扩展的初始化 374 11.2.5.调试会话状态的变化 379 11.2.6.KnownStructOutput 379 11.2.7.退出调试扩展 379 11.2.8.Help命令的实现 380 11.2.9.dumptree命令的实现 381 11.2.10.KnownStructOutput函数的实现 384 11.2.11.取消命令的实现387 11.2.12.版本 389 11.2.13.调试扩展的构建389 11.3.小结 390 第12章.64位调试 391 12.1.Microsoft 64位系统 391 12.1.1.操作系统简介 392 12.1.2.在WOW64运行的32位程序 393 12.2.Windows x64带来的变化395 12.2.1.第1章—调试工具简介 396 12.2.2.第2章—调试器简介 397 12.2.3.第3章—调试器揭密 407 12.2.4.第5章—内存破坏之一—栈 411 12.2.5.第6章—内存破坏之二—堆 411 12.2.6.第7章—安全 412 12.2.7.第8章—进程间通信 413 12.2.8.第11章—编写定制的调试扩展414 12.3.小结 414 第13章.事后调试 415 13.1.转储文件基础 415 13.1.1.通过调试器来生成转储文件 417 13.1.2.通过ADPlus来生成转储文件 420 13.1.3.内核态转储文件的创建 421 13.2.转储文件的使用 423 13.2.1.转储文件的分析:访问违例 424 13.2.2.转储文件的分析:句柄泄漏 425 13.3.Windows错误报告 429 13.3.1.Dr.Watson 429 13.3.2.Windows错误报告的系统架构 434 13.4.企业错误报告 446 13.4.1.设置企业错误报告 447 13.4.2.通过企业错误报告来报告错误 449 13.5.小结 451 第14章.功能强大的工具452 14.1.调试诊断工具 452 14.1.1.分析内存泄漏或者句柄泄漏 453 14.1.2.编写定制的分析脚本 455 14.2.扩展命令!analyze 457 14.2.1.故障程序 457 14.2.2.分析结果 458 14.2.3.故障的跟进人员 462 14.3.小结 463 第15章.Windows Vista基础 464 15.1.第1章—调试工具简介 464 15.2.第2章—调试器简介 465 15.2.1.用户访问控制的副作用 465 15.2.2.启用内核态调试器 467 15.2.3.地址空间布局的随机化 468 15.3.第6章—内存破坏之二—堆 469 15.4.第7章—安全性 473 15.4.1.用户访问控制 474 15.4.2.调试器的UAC 475 15.4.3.注册表和文件虚拟化 479 15.5.第8章—进程间通信 481 15.6.第9章—资源泄漏 482 15.7.第10章—同步482 15.7.1.轻量读写锁 482 15.7.2.条件变量 483 15.7.3.单次初始化 484 15.7.4.增强线程池 484 15.8.第11章—编写定制的调试扩展 484 15.9.第13章—事后调试485 15.10.小结487 附录A.应用程序验证器的测试设置488
一个很不错的C#录音控件源码,如果觉得超值请好评。谢谢! 以下文字是帮您提供提示出错的解决方案 在用VS2005编写一个非常简单的播放器程序时编译是OK的。当我Debug运行的时候遇到了问题,现象如下: LoaderLock was detected Message: DLL“C:WINDOWSassemblyGACMicrosoft.DirectX1.0.2902.0__31bf3856ad364e35Microsoft.DirectX.dll”正试图在 OS 加载程序锁内执行托管代码。不要尝试在 DllMain 或映像初始化函数内运行托管代码,这样做会导致应用程序挂起。 出错代码位置如下: //打开一个的Video文件 myVideo = new Video(openFileDialog1.FileName); 去网上查了一下资料:.NET2.0增加了42种非常强大的调试助手(MDA,Loaderlock是其之一。Loaderlock检测在一个拥有操作系统loader lock的线程上(如上例的video的运行线程)运行托管代码的情况。这样做有可能会引起死锁,并且有可能在操作系统加载器初始化DLL前被使用。虽然这样做很有必要,但在进行开发调试的时候,实在太麻烦。解决方案如下: 1.改注册表 在HKEY_LOCAL_MACHINESOFTWAREMicrosoft.NETFramework下面增加一个String,值为"0" 不过这样做,在该计算机上所有基于.NET2.0开发都得不到MDA的好处。 2.为项目增加一个配置文件. 3.直接修改项目设置 最简单的方法,在"Debug"菜单下----"Exceptions"----"Managed Debugging Assistants"勾掉"LoaderLock") 再Debug,OK,一切搞定

15,471

社区成员

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

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