Безопасно ли вызывать функцию std :: thread :: join в Win32 DLL_PROCESS_DETACH? [Дубликат]

Было опубликовано много хороших ответов, но я хотел бы добавить еще один.

Не все числа могут быть представлены с помощью float / double. Например, будет представлено число «0,2» как «0.200000003» в одинарной точности в стандарте по плавающей точке IEEE754.

Модель для хранения действительных чисел под капотом представляет собой число с плавающей запятой в качестве

Хотя вы можете легко ввести 0.2, FLT_RADIX и DBL_RADIX равно 2; не 10 для компьютера с FPU, который использует «Стандарт IEEE для двоичной арифметики с плавающей запятой (ISO / IEEE Std 754-1985)».

. Точно так же трудно точно представлять такие числа. Даже если вы укажете эту переменную явно без какого-либо промежуточного вычисления.

0
задан aleksv 6 March 2016 в 15:22
поделиться

1 ответ

Вы не можете дождаться выхода потока в DllMain (). Если поток уже не выходил к тому времени, когда был получен DLL_PROCESS_DETACH, так будет всегда тупиковый. Это ожидаемое поведение.

Причиной этого является то, что вызовы DllMain () сериализуются через блокировку загрузчика. Когда вызывается ExitThread (), он запрашивает блокировку загрузчика, чтобы он мог вызвать DllMain () с помощью DLL_THREAD_DETACH. Пока этот вызов не закончен, поток все еще запущен.

Итак, DllMain ждет выхода потока, и поток ожидает выхода DllMain, классической ситуации взаимоблокировки.

См. Также Рекомендации по использованию библиотеки динамической ссылки в MSDN.

Решение состоит в том, чтобы добавить новую функцию в вашу DLL для приложения для вызова перед выгрузкой библиотеки DLL. Как вы уже отмечали, ваш код уже отлично работает при явном вызове.


В случае, когда требования обратной совместимости делают невозможным добавление такой функции, и если вы должны иметь рабочие потоки, рассмотреть возможность разделения вашей DLL на две части, одна из которых динамически загружается другой. Динамически загруженная часть будет содержать (как минимум) весь код, необходимый для рабочих потоков.

Когда DLL, которая была загружена самим приложением, получает DLL_PROCESS_DETACH, вы просто устанавливаете событие, чтобы сигнализировать потоки чтобы выйти, а затем немедленно вернуться. Один из потоков должен быть назначен для ожидания всех остальных, а затем освободить вторую DLL, которую вы можете безопасно использовать с помощью FreeLibraryAndExitThread () .

(В зависимости от обстоятельства, и в частности, если рабочие потоки выходят и / или новые, созданные в рамках обычных операций, вам может потребоваться быть очень осторожными, чтобы избежать условий гонки и / или взаимоблокировок, это, вероятно, будет проще, если вы использовали пул потоков и обратные вызовы, а не создание рабочих потоков вручную.)


В частном случае, когда потокам не нужно использовать какие-либо, но самые простые Windows API, возможно, будет возможно использовать пул потоков и рабочие обратные вызовы, чтобы избежать необходимости во второй DLL. После того, как вышли вызовы, которые вы можете проверить с помощью WaitForThreadpoolWorkCallbacks () , безопасно, чтобы библиотека была выгружена - вам не нужно ждать, когда сами потоки будут завершены.

Ловушка заключается в том, что обратные вызовы должны избегать любых API Windows, которые могут занять блокировку загрузчика. Не документировано, какие вызовы API безопасны в этом отношении, и это зависит от разных версий Windows. Если вы вызываете что-то более сложное, чем SetEvent или WriteFile, скажем, или если вы используете библиотеку, а не собственные функции Windows API, вы не должны использовать этот подход.

10
ответ дан Harry Johnston 27 August 2018 в 08:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: