2009-11-06 2 views
9

Кажется, что когда поток создается из DllMain после DLL_PROCESS_ATTACH, он не начнется, пока все DLL не будут загружены. Поскольку мне нужно убедиться, что поток работает до того, как я продолжу, я получаю тупик. Есть ли способ заставить поток начать?Создание потока в DllMain?

ответ

10

Вы не должны делать какие-либо API-вызовы, особенно для таких вещей, как создавать темы или окна, из DLLMain. Раймонд Чен писал об этом много раз; вот one, что особенно актуально.

+10

CreateThread - это одна из немногих вещей, которые вы можете сделать внутри DllMain, потому что это вызов kernel32, который, как гарантируется, уже загружен. –

+2

@Ben Voigt, но будьте предельно осторожны, так как легко получить мертвую блокировку, если текущий вызов DllMain попросят дождаться возврата из нового потока. – mloskot

+0

@mloskot: Вызывать функции ожидания в 'DllMain' очень плохо, независимо от того, какой объект вы ожидаете. Как правило, любой поток, выполняющий код из DLL, должен иметь счетчик ссылок на эту DLL, за исключением того, что код получается из-под него. Это предотвращает возникновение проблемы, поскольку «DllMain» тогда не будет вызываться (для отсоединения процесса) до тех пор, пока поток работает. –

5

Нет. Вы не должны вызывать CreateThread (или любую вариацию) из DllMain. Попытка синхронизации приведет к тупиковой ситуации. Что именно ты пытаешься сделать?

Best Practices for Creating DLLs

+7

Нет ничего плохого в вызове CreateThread, но нет никакого способа избежать приостановки потока до тех пор, пока обработка DllMain не завершится в родительском потоке. –

0

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

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

+2

Первый абзац здесь является чрезмерным обобщением. Совершенно нормально звонить в библиотеки DLL, которые, как вы знаете, уже были загружены до вас. В общем и в большинстве случаев это означает только KERNEL32.DLL, который может звучать как ограничение калеки, но вы можете использовать его, чтобы вырваться из этой ситуации. –

+2

http://blogs.msdn.com/oldnewthing/archive/2007/09/04/4731478.aspx –

+0

Спасибо Integer Poet. Это точно отвечает на вопрос, который я пришел сюда, чтобы решить. –

5

Что делает ваша нить?

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

Нет никакого способа обойти это. Нить не может начаться только после обработки DLL_THREAD_ATTACH, и это не может произойти, когда ваш первый поток находится внутри DllMain. Единственный возможный способ - начать новый процесс (который имеет независимую блокировку загрузчика и не будет блокировать вас в ожидании).

+0

Я попробовал простое использование 'CreateThread()' для очень простой рабочей функции в 'DLLMain()' во время обработки сообщений DLL_PROCESS_ATTACH. Функция потока использовала 'Sleep()' в течение 1000 миллисекунд. Все работало нормально. Я мог видеть сообщения 'DLL_THREAD_ATTACH' и' DLL_THREAD_DETACH' сообщения из начального потока, выполняющего 'DLL_PROCESS_ATTACH', и поток, созданный во время обработки присоединения. Однако этот рабочий поток не сделал ничего, кроме 'Sleep()'. Предполагается, что вызовы Kernel32.dll будут в порядке. Протестировано с помощью VS 2005 Windows 7. –

+0

Как ни странно, это единственный ответ, который отвечает на заданный вопрос. Я не знаю, почему ОП решил принять ответ, а это не так. – IInspectable

Смежные вопросы