4

У меня есть поток A, который создает другой поток B, чем поток A ждет, используя WaitForSingleObject, чтобы ждать, пока нить B не умрет.WaitForSingleObject с ручкой потока застревают во время работы regsvr32.exe

Проблема в том, что хотя поток B возвращается из потока thread_func, поток A не получает сигнал!.

Я знаю, потому что я добавил следы (OutputDebugString) в конец thread_func (основная функция потока B), и я вижу, что поток B заканчивает выполнение, но нить A никогда не выходит из WaitForSingleObject.

Теперь я должен добавить, что этот код находится в COM-объекте, и описанный выше сценарий происходит, когда я вызываю regsvr32.exe (он застревает!), Поэтому я считаю, что поток A исходит из DLLMain.

Любые идеи, почему нить А не сигнализируется?!?!

ответ

14

Вы можете столкнуться с проблемой блокировки погрузчика. Windows, имеет внутренний критический раздел, который блокируется всякий раз, когда DLL загружается/выгружается или когда поток запускается/останавливается (DllMain всегда вызывается внутри этой блокировки). Если ваш ожидающий поток A заблокировал этот критический раздел (т. Е. Вы где-то ожидаете от DllMain), в то время как другой поток B пытается завершить работу и пытается получить критический раздел загрузчика, у вас есть ваш тупик.

Чтобы узнать, где находится тупик, просто запустите приложение из отладчика VS IDE и после его застревания прекратите выполнение. Затем просмотрите все текущие потоки и обратите внимание на стек каждого из них. Вы должны следить за каждым стекем и видеть, что ждет каждый поток.

+0

Вы абсолютно правы !!! Я не знал, что он работает так! Поэтому я предполагаю, что я буду использовать другое событие, чтобы сигнализировать поток конца потока B. – TCS

+0

+1 на этот ответ. Если DllMain вызывает какой-либо нетривиальный путь кода (включая код, который вызывает системные и API-вызовы), просто запрашивает проблемы. – selbie

4

Я думаю, что @DXM является правильным. Документация о том, что вы можете или не можете сделать внутри DllMain, является редкой и труднодоступной, но суть в том, что вы должны, как правило, поддерживать ее до минимума - инициализировать внутренние переменные и т. Д., Но это о ней.

Другой момент, который я бы сделал, заключается в том, что вы, как правило, должны не «звонок» regsvr32.exe - когда-либо.

RegSvr32 в основном только оболочка, которая загружает DLL в его адресное пространство с LoadLibrary, вызовы GetProcAddress, чтобы получить адрес функции с именем DllRegisterServer, затем вызывает эту функцию. Гораздо чище (и, в конечном счете, проще) выполнять работу самостоятельно, примерно так:

HMODULE mod = LoadLibrary(your_COM_file); 
register_DLL = GetProcAddress(mod, "DllRegisterServer"); 
if (register_DLL == NULL) { 
     // must not really be a COM object... 
} 

if (S_OK != register_DLL()) { 
     // registration failed. 
} 
+0

Извините, но я не понял почему 'regsvr32' плохой и почему писать собственный код является более ранним –

+0

Вы не видите проблему с созданием всего процесса, просто для вызова одной функции? Здесь мы имеем четыре строки кода, которые работают. Ваш код для использования 'system' должен быть не менее трех строк и еще не работает - и к тому моменту, когда вы его заработаете, будет значительно больше (и больше, чем у вас, * и * более четырех - совсем немного). –

+1

Я не вижу упоминания 'system'. Скорее всего, OP запускает regsvr32.exe из окна консоли вручную (как и многие из нас), чтобы зарегистрировать его библиотеку COM, и он застрял из-за этой системной блокировки. Поэтому я полностью не понимаю, как реализовать дополнительный инструмент для регистрации этой библиотеки COM может быть полезным или даже актуальным для вопроса. Ваши методы будут делать то же самое, и его библиотека будет придерживаться того же –