DLL_PROCESS_DETACH остался только один поток

--- симптомы

Когда я загружаю свою Dll из подпотока хост-приложения, и хост-приложение закрывается, при вызове Dll_PROCESS_DETACH остается только 1 поток. Это плохо. Это вызывает утечку памяти, и требуемая очистка не может быть выполнена.

Когда я загружаю свою Dll из MAIN-потока хост-приложения, и хост-приложение закрывается, все потоки, созданные в Dll, все еще работают при вызове Dll_PROCESS_DETACH. Это хорошо, потому что я могу сделать всю необходимую работу по очистке.

Мой Dll_PROCESS_ATTACH НЕ содержит кода. Поток не создается, функция API не вызывается.

-- цель этой Dll, вариант использования

Мне нужна Dll, которая может работать в различных хост-приложениях, где я не знаю, когда именно моя Dll загружается и выгружается.

Некоторые из этих хост-приложений, очевидно, загрузить мою Dll из потока, например. этот поток запускает сценарий, и сценарий использует экспортированные функции моей библиотеки DLL.

Общая проблема заключается в следующем: когда Dll впервые загружается из подпотока хост-приложения, она не выгружается должным образом, потому что все потоки, казалось, были удалены при вызове Dll_PROCESS_DETACH. Это не только вызывает утечку памяти, но и не может выполнять некоторую внутреннюю работу по очистке, останавливая потоки и выполняя окончательное соединение сокета, используемое для связи с сервером.

Все это прекрасно работает, когда Dll загружается из основного потока (на моем тестовом хосте) или в конкретных тестируемых хост-приложениях.

Две трассировки стека сеансов отладки C++ Dll, работающей в Visual Studio 17. Первый — плохой, когда 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 из подпотока или основного потока хост-приложения.

Есть ли что-то, что можно сделать с помощью настроек компилятора или компоновщика, или обходной путь?

Заранее благодарю за каждую подсказку.

Функция уничтожения просто уничтожает объект при вызове DLL_PROCESS_DETACH. Этот объект создается при первом вызове экспортируемой функции. Итак, вне DllMain. Этот объект выполняет всю работу, которую необходимо выполнить в моей DLL. Он запускает несколько потоков, устанавливает соединение с сокетом и так далее. Уничтожение не уничтожает Dll, это невозможно, потому что хост-приложение делает это при вызове FreeLibrary. Но, похоже, поскольку мой объект запускает поток, вызывается DLL_PROCESS_DETACH, когда ВСЕ потоки просто удаляются, не давая мне возможности очистить.

nullptr 23.05.2019 00:23

Имя DllTest_app неудачное, извините. Это просто имя объекта, созданного при первом вызове экспортируемой функции DLL. Это не сама DLL. Но этот объект создает потоки, которые должны завершиться обычным образом. Но это невозможно, и в этом проблема. Пожалуйста, загрузите очень маленький образец проекта по ссылке, где я мог бы воспроизвести эту проблему:

nullptr 23.05.2019 00:40

Пример проекта: filedropper.com/testdll2_1 Как использовать: создать папку c:\debuglib проект сборки (win64, отладка) Запустить. Нажмите «Загрузить DLL, создайте поток в DLL». Нажмите «Выгрузить DLL». В файле dllmain.cpp DLL_PROCESS_DETACH не вызывается! Когда вы закрываете приложение, вызывается DLL_PROCESS_DETACH, но все потоки (dll_test_thread_function) завершаются. Это проблема. Спасибо за помощь.

nullptr 23.05.2019 00:55
3 метода стилизации элементов HTML
3 метода стилизации элементов HTML
Когда дело доходит до применения какого-либо стиля к нашему HTML, существует три подхода: встроенный, внутренний и внешний. Предпочтительным обычно...
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
0
3
404
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Похоже, что один из потоков в вашем приложении вызывает exit(), что приводит к вызову ExitProcess() API - https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-exitprocess

Как описано в документации ExitProcess, он завершает все потоки, а затем вызывает DllMain() с DLL_PROCESS_DETACH.

Вызов ExitProcess также может привести к взаимоблокировке, если завершенные потоки содержат мьютекс, который пытается получить последний поток, выполняющий DLL_PROCESS_DETACH.

Другие вопросы по теме