Я использую библиотеку miniaudio для реализации аудиомодуля в библиотеке SFML 3.x с открытым исходным кодом.
В попытке упростить управление нашими аудиоресурсами я удалил подсчет ссылок во время выполнения вместо более простого статического объекта-менеджера (см. SFML/pull/2974). >
Мои изменения вызвали проблемы в Windows: любое приложение, использующее аудиомодуль, зависает при завершении работы. После некоторого расследования, проведенного @binary1248, и некоторых дополнительных тестов мной, мы поняли, что проблема связана с тем, как Windows обрабатывает atexit и завершение потока при сборке в виде DLL (общая библиотека). Подробнее см. в этой статье.
По сути, в рамках процедуры завершения процесса среда выполнения Win32 принудительно завершает любой оставшийся поток, не присоединяясь к ним и не отправляя уведомление об отключении потока. Это означает, что попытка очистить ресурсы miniaudio с помощью atexit (именно так вызываются деструкторы статических объектов C++) приведет к зависанию программы на условной переменной подождите во внутренних устройствах miniaudio (
Код: Выделить всё
ma_event_wait(&pDevice->stopEvent)
В качестве обходного пути я попробовал проверить, жив ли поток, прежде чем ждать, используя это решение, которое предполагает, что достаточно проверить WaitForSingleObject(threadHandle, 0) == WAIT_TIMEOUT. Хотя это решило проблему на моем компьютере, это не помогло на других установках Windows, и я все равно считаю, что это неопределенное поведение.
Я хотел бы чисто присоединиться к miniaudio' внутренние потоки s перед завершением работы программы. Как это сделать?
Проблема
Насколько я понимаю, происходит следующее:
< ol>
[*]Общая DLL SFML инициализирует miniaudio, который внутри порождает некоторые рабочие потоки.
[*]После завершения процесса функция atexit процесса стек обрабатывается.
- Здесь нет ничего полезного, поскольку очистка miniaudio зарегистрирована в общем стеке функций atexit SFML.
Код: Выделить всё
ExitProcess
- Это включает рабочие потоки miniaudio. li>
- В этом проблема!
- Теперь уже слишком поздно для процедуры очистки. присоединиться к рабочим потокам, поэтому он будет зависать на неопределенный срок в ожидании условной переменной, которая больше не существует.
Вопрос
Можно ли, даже модифицировав сам miniaudio, чисто присоединяться к рабочим потокам при завершении программы, даже если эти потоки были запущены из общей библиотеки?
В принципе, можно ли вызвать процедуру очистки miniaudio до того, как произойдет ExitProcess? p>
Если нет, то можно ли как-то добиться желаемого результата, не требуя от разработчика приложения вручную вызывать функцию очистки в конце основного?
Пример
Код: Выделить всё
// main.cpp
#include
#include "dll.h"
int main()
{
std::cout
Подробнее здесь: [url]https://stackoverflow.com/questions/78507797/joining-a-thread-started-by-a-dll-prior-to-program-termination-on-windows[/url]