首页 > 解决方案 > DLL_PROCESS_DETACH 只剩下一个线程

问题描述

- - 症状

Dll_PROCESS_DETACH当我从主机应用程序的子线程加载我的 Dll 并关闭主机应用程序时,调用时只剩下 1 个线程。这是不好的。它会导致内存泄漏并且无法完成所需的清理。

当我从主机应用程序的主线程加载我的 Dll 并关闭主机应用程序时,在 Dll 中创建的所有线程在Dll_PROCESS_DETACH调用时仍在运行。这很好,因为我可以完成所有需要的清理工作。

Dll_PROCESS_ATTACH的没有代码。没有创建线程,没有调用 API 函数。

-- 这个 Dll 的用途,用例

我需要一个可以在各种主机应用程序中运行的 Dll,我不知道我的 Dll 何时加载和卸载。

其中一些主机应用程序显然从一个线程中加载了我的 Dll,例如,该线程正在运行一个脚本,并且该脚本使用了我的 Dll 的导出函数。

一般问题是:当第一次从宿主应用程序的子线程加载DLL时,它没有正确卸载,因为Dll_PROCESS_DETACH调用时似乎所有线程都被删除了。这不仅会导致内存泄漏,而且它不能做一些内部清理工作,停止线程并进行最终的套接字连接,用于与服务器通信。

当 Dll 从主线程(在我的测试主机中)或在它测试的特定主机应用程序中加载时,所有这些都可以正常工作。

在 Visual Studio 17 中运行的 c++ Dll 的调试会话的两个堆栈跟踪。第一个是坏的,其中 Dll 从子线程加载。

第二个是好的,从主线程加载 Dll。

// exit stack Dll  Dll loaded in subthread ; breakpoint in `Dll_PROCESS_DETACH` This is BAD


DllTest.dll!DllTest_app::~DllTest_app() Line 176    C++
    [External Code] 
    DllTest.dll!DllTest_app::destroy() Line 208 C++
    DllTest.dll!DllMain(HINSTANCE__ * hModule, unsigned long ul_reason_for_call, void * lpReserved) Line 43 C++
    [External Code] 
    DllTest_test.exe!exit_or_terminate_process(const unsigned int return_code) Line 130 C++
    DllTest_test.exe!common_exit(const int return_code, const _crt_exit_cleanup_mode cleanup_mode, const _crt_exit_return_mode return_mode) Line 271    C++
    DllTest_test.exe!exit(int return_code) Line 283 C++
    [External Code] 
// exit stack Dll loaded in mainthread; breakpoint in `Dll_PROCESS_DETACH` This is GOOD


DllTest.dll!DllTest_app::~DllTest_app() Line 175    C++
    [External Code] 
    DllTest.dll!DllTest_app::destroy() Line 208 C++
    DllTest.dll!DllMain(HINSTANCE__ * hModule, unsigned long ul_reason_for_call, void * lpReserved) Line 43 C++
    [External Code] 
    DllTest_test.exe!DllTestWrap::Unload(int code, int bdeleteerror) Line 139   C++
    DllTest_test.exe!DllTestWrap::~DllTestWrap() Line 66    C++
    [External Code] 
    DllTest_test.exe!_execute_onexit_table::__l22::<lambda>() Line 198  C++
    DllTest_test.exe!__crt_seh_guarded_call<int>::operator()<void <lambda>(void),int <lambda>(void) & __ptr64,void <lambda>(void) >(__acrt_lock_and_call::__l3::void <lambda>(void) && setup, _execute_onexit_table::__l22::int <lambda>(void) & action, __acrt_lock_and_call::__l4::void <lambda>(void) && cleanup) Line 199   C++
    DllTest_test.exe!__acrt_lock_and_call<int <lambda>(void) >(const __acrt_lock_id lock_id, _execute_onexit_table::__l22::int <lambda>(void) && action) Line 882   C++
    DllTest_test.exe!_execute_onexit_table(_onexit_table_t * table) Line 222    C++
    DllTest_test.exe!common_exit(const int return_code, const _crt_exit_cleanup_mode cleanup_mode, const _crt_exit_return_mode return_mode) Line 211    C++
    DllTest_test.exe!exit(int return_code) Line 283 C++
    [External Code] 

如何实现,在调用 Dll_PROCESS_DETACH 时,无论 Dll 是从主机应用程序的子线程还是主线程加载,在 Dll 中创建的所有线程仍在运行且未终止。

有没有可以通过编译器或链接器设置或解决方法来完成的事情?

预先感谢您的每一个提示。

标签: multithreadingdll

解决方案


似乎您的应用程序中的线程之一调用 exit() 导致调用 ExitProcess() API - https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-exitprocess

如 ExitProcess 文档中所述,它终止所有线程,然后使用 DLL_PROCESS_DETACH 调用 DllMain()。

如果终止的线程持有一个互斥体,执行 DLL_PROCESS_DETACH 的最后一个线程试图获取该互斥体,则调用 ExitProcess 也可能导致死锁。


推荐阅读