Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/126.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 线程对象的WaitForSingleObject在DLL卸载中不工作_C++_Multithreading_Winapi_Dll - Fatal编程技术网

C++ 线程对象的WaitForSingleObject在DLL卸载中不工作

C++ 线程对象的WaitForSingleObject在DLL卸载中不工作,c++,multithreading,winapi,dll,C++,Multithreading,Winapi,Dll,在卸载DLL时,我偶然发现了Windows线程机制的一个意外行为。A有一组工作线程对象,我正试图在通过DllMain DLL_进程_分离卸载DLL时优雅地完成它们。代码非常简单,我确实发送了一个事件来完成线程的等待循环: WaitForSingleObject( ThrHandle, INFINITE ); CloseHandle( ThrHandle ); 然而,WaitForSingleObject挂起了整个事件。如果我在卸载DLL之前执行它,它就可以正常工作。如何修复此行为?除非在收到D

在卸载DLL时,我偶然发现了Windows线程机制的一个意外行为。A有一组工作线程对象,我正试图在通过DllMain DLL_进程_分离卸载DLL时优雅地完成它们。代码非常简单,我确实发送了一个事件来完成线程的等待循环:

WaitForSingleObject( ThrHandle, INFINITE );
CloseHandle( ThrHandle );
然而,WaitForSingleObject挂起了整个事件。如果我在卸载DLL之前执行它,它就可以正常工作。如何修复此行为?

除非在收到DLL\u进程\u分离时线程已经退出,否则这样做将始终死锁。这是预期的行为

原因是对DllMain的调用是通过加载程序锁序列化的。调用ExitThread时,它会声明加载程序锁,以便可以使用DLL\u THREAD\u DETACH调用DllMain。在该调用完成之前,线程仍在运行

因此DllMain正在等待线程退出,而线程正在等待DllMain退出,这是一种典型的死锁情况

另请参见MSDN

解决方案是在DLL中添加一个新函数,以便应用程序在卸载DLL之前调用。正如您所注意到的,当显式调用时,您的代码已经工作得非常好了

在向后兼容性要求中添加这样一个函数是不可能的,如果你必须有工作者线程,考虑把你的DLL分裂成两个部分,其中一个部分被另一个部分动态加载。动态加载的部分至少包含工作线程所需的所有代码

当应用程序本身加载的DLL接收到DLL_PROCESS_DETACH时,您只需将事件设置为通知线程退出,然后立即返回。必须指定其中一个线程等待所有其他线程,然后释放第二个DLL,您可以安全地使用它

根据具体情况,特别是如果作为常规操作的一部分正在退出工作线程和/或正在创建新的工作线程,您可能需要非常小心以避免争用条件和/或死锁;如果使用线程池和回调,而不是手动创建工作线程,那么这可能会更简单

在线程只需要使用最简单的Windows API而不需要使用任何API的特殊情况下,可以使用线程池和工作回调来避免需要第二个DLL。一旦回调退出(您可以使用它进行检查),卸载库是安全的——您不需要等待线程本身退出


这里的问题是回调必须避免任何可能占用加载程序锁的Windows API。在这方面,没有记录哪些API调用是安全的,并且在不同版本的Windows之间有所不同。如果您调用的是比SetEvent或WriteFile更复杂的函数,或者如果您使用的是库而不是本机Windows API函数,则不能使用这种方法。

DllMain内部的死锁是一个非常常见的问题。如果您正在等待的代码执行任何操作以卸载另一个DLL,那么加载程序锁将始终挂起您的程序。使用调试器诊断此问题。您应该已经做了一些事情来记录这个问题,比如发布该线程的调用堆栈。总的来说,在德国等待任何事情都是危险的,应该避免。不,僵局是不可能的。工作线程所做的就是等待一个事件。WaitForSingleObject事件,无限;我在调用WaitForSingleObject ThrHandle之前发送了它,听起来好像你不知道加载程序锁是什么意思,你在等待两个同步对象。如果他们没有按照正确的顺序得到信号,那么你就死锁了。谷歌搜索得很好。当然不是,装载机锁没有锁好。坚持认为您没有问题无助于我们帮助您,发布stack trace.DllMain调用被序列化的消息。当工作线程退出时,它会尝试发送DLL\u线程\u分离通知,但在DLL\u进程\u分离完成之前,它无法发送通知。因此出现了僵局。您需要在DLL中创建一个函数,以便应用程序在卸载DLL之前调用。该函数可以关闭工作线程。链接到官方文档:…@HansPassant:您的意思是,应用程序可能已禁用每个DLL的线程通知,包括C运行时库?:-你不知道这对我有多大帮助+1.