984259h Просто смотрите что у Вас получается. выполняется FreeLibrary из-за чего вызывается DllMain.PROCESS_DETACH далее сразу же устанавливается Event и уничтожается Если это происходит не под отладчиком, то система автоматически перед уничтожением переключается на поток ожидающий этот Event. Отладчик же блокирует автоматическое переключение потоков и второй поток под отладчиком получает управление только когда Event вообще уже уничтожен. Одно из возможных решений. Перенесите CloseHandle(hShutdownEvent); в Thread_func.
к стати при запуске этого екзе сразу 4 потока (почему 4-ри ?) через 10 секунд вылетает MessageBoxA и остается 1 поток (если не нажав MessageBoxA то есть поток должен остановится до нажатия кнопки ) после чего ( через некоторое время, я так понял что системой аварийно завершается )
PowerASM спасибо как вы говорили на счет "(поставить Sleep между Set и Close, либо SwitchToThread)" поставил Sleep(1000) ну в "Перенесите CloseHandle(hShutdownEvent); в Thread_func." а также поставил CloseHandle(hThreadMainConn); вот только с потоками немного не ясно почему их 4ри
Я тут с завистью облизываюсь на ваши эксперименты, т.к. давно хочу поработать с потоками. Но пока обхожусь без. Решил посмотреть сколько потоков в простой программе на Дельфи. Их 2 - 1 видимо обработчик Виндовых сообщений, второй - собственно обработка событий самого Дельфи. У вас наверное 3-й штатный поток - это обработка эвентов... Т.е. нет никакой мистики.
valterg Ну если шаманить то картина такая получается я загружаю библиотеку получаю уведомление аттач и сразу создаю поток (который крутится в цикле ожидая события на завершения с задержкой 100 миллисек. -для обработки след. кода). Естественно сам процесс это поток 1 + загрузка либы (LoadLibraryA) + 1 и мой созданный + 1 в сумме = 3 пока все ок. Теперь мне необходимо выгрузить длл с ап процесса и тут следующая ситуация. Создается поток для выгрузки (FreeLibrary), сначала получаю уведомление на детач устанавливаю событие на завершения потока созданого на аттач либы после чего жду 1 сек на проработку. Мой поток возвращает на управление то есть пока все норм.Как только с детач выхожу и процесс должен завершится получается deadlock так как правильно сделать что код корректно завершился ?
984259h Скорее всего это ожидание освобождения критической секции LdrpLoaderLock, так как вы делаете запрежённые действия.
Clerk Я не совсем Вас понял. Вы имеете ввиду что нельзя делать вызов CreateThread на длл аттач (из -за чего и ) ?
984259h Если вы создадите поток из InitRoutine модуля, то он будет ждать освобождения указанной выше кс. А это произойдёт когда текущий поток вернётся из длл, а далее из загрузчика, который перед этим освободит кс.
Всю тему не смотрели – лишь быстро прокомментируем кусок кода из #18: >nEvent = WaitForMultipleObjects(1,&hShutdownEvent,FALSE,100); Здесь нет необходимости делать таймаут 100мс (если это делается в целях какого-то другого эксперимента, тогда пренебрегай этим). >case DLL_PROCESS_DETACH: >SetEvent(hShutdownEvent); Вот здесь выставляешь события для другого потока, да. Однако после сигнализации ты ничего не ждёшь и просто возвращаешь TRUE из DllMain – может получиться так, что длл выгрузится до того, как выполняющий код в функции Thread_func поток завершится. Т.е. память, занимаемая функцией Thread_func, освободится – и при попытке исполнить что-либо оттуда произойдёт нарушение доступа. Не слишком хорошей идеей для решения этой проблемы могло бы стать ожидание в DllMain на hThreadMainConn после сигнализации hShutdownEvent – здесь, в зависимости от внутренней реализации лоадера, мы можем получить или не получить дедлок, поскольку при завершении потока должна быть вызвана DllMain(DLL_THREAD_DETACH), а она полагается нереентерабельной и вход в неё охраняется [ага, видим – в первом случае ты получаешь как раз это]. Ещё одним решением могло бы стать введение дополнительного события – OkayToUnloadEvent – на котором бы стоило ожидать внутри DllMain после сигнализации hShutdownEvent. Событие OkayToUnloadEvent в этом случае необходимо было бы сигнализировать при выходе из Thread_func с помощью внешней по отношению к dll функции SetEventAndExitThread(), которая сигнализирует событие и вызывает 'ExitThread()', не возвращаясь в вызываемый код. В качестве третьего варианта можем предложить бампнуть счётчик загрузок при создании потока из себя (вызовом LoadLibrary(self)), а при выходе из этого потока использовать FreeLibraryAndExitThread() – в отличие от гипотетической SetEventAndExitThread() эта функция рельно существует. Следует учитывать, что в последнем случае exe теряет способность точно контролировать момент выгрузки dll – при существовании рабочего потока она будет удалена из адресного пространства не после вызова FreeLibrary(), а лишь тогда, когда рабочий поток вызовет FreeLibraryAndExitThread(). Общая рекомендация – строить код таким образом, чтобы просто не возникало ситуаций, когда dll неявно создаёт потоки и при этом может быть свободно выгружена.
Sol_Ksacap Я уже об этом думал и делал после установки еванта Sleep(1000) или SwitchToThread() как говорил PowerASM. А если код с++ не представлять что это единое целое а представить что он состоит нескольких строк asm тогда как нельзя мне кажется говорить ( )
>Sleep(1000) или SwitchToThread() Не делай этого. Для правильно построенного кода подобное не понадобится. Для неправильного – лишь уменьшит вероятность проявления проблемы, но не решит её. Редкая, трудновоспроизводимая проблема хуже, чем легковоспроизводимая. Код (Text): nEvent = WaitForMultipleObjects(1,&hShutdownEvent,FALSE,100); (1) call [__imp_WaitForMultipleObjects] (2) mov [ebp + 8], eax Представь, что рабочий поток сейчас выполнил строку (1) и в недрах ядра ожидает сигнализации объекта. В это время основной поток выполняет код в DllMain для случая DLL_PROCESS_DETACH: сигнализирует событие и выходит из DllMain, после чего dll убирается из адресного пространства процесса. Через некоторое время рабочий поток продолжает выполнение – выполняет то и это, пока не придёт к выходу из функции WaitForMultipleObjects, после чего он должен будет продолжить выполнение строчки (2). А на этом месте уже пусто. Или хуже. Допустим, пока рабочий поток стремился к выходу из WaitForMultipleObjects, была загружена ещё одна dll и на месте строки (2) – совсем другой код. Окей, это понятно – говорим сие лишь к тому, что как код не представляй (си\асм\етц) – итог один.
Clerk задача такая Нужно что бы на подгрузку длл создавался бекконнект (тоесть когда длл загрузилась она постоянно пыталась соединится с определенный адресом ) а также что бы можно было выгрузить длл с процесса.