DLL_PROCESS_DETACH仅剩一个线程

时间:2019-05-22 13:30:09

标签: multithreading dll

---症状

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

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

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

-此Dll的用途,用例

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

其中一些主机申请明显 从线程内加载我的Dll,例如该线程正在运行一个脚本,并且该脚本使用了我的Dll的导出功能。

一般的问题是:第一次从主机应用程序的子线程加载Dll时,由于无法调用Dll_PROCESS_DETACH似乎删除了所有线程,因此无法正确卸载Dll。这不仅会导致内存泄漏,还无法进行一些内部清理工作,停止线程以及进行最终的套接字连接(用于与服务器通信)。

当从主线程(在我的测试主机中)或在它测试的特定主机应用中加载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中创建的所有线程仍在运行并且不会终止。

是否可以通过编译器或链接器设置或替代方法来完成某些工作?

预先感谢您的提示。

1 个答案:

答案 0 :(得分:0)

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

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

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