Ошибка блокировки загрузчика
Я строю на C++ DLL, написав код на C#.
Я получаю ошибку, говоря
LoaderLock обнаружен. Сообщение: Попытка управляемого выполнения внутри блокировки загрузчика ОС. Не пытайтесь запускать управляемый код внутри функции инициализации DllMain или изображения, так как это может привести к зависанию приложения.
Я попытался выяснить, что именно означает эта ошибка, но я рисую бессмысленные статьи, в основном говоря, что это всего лишь предупреждение, и я должен отключить это в Visual Studio. Другие решения, по-видимому, связаны с ITunes, или эта проблема возникает при программировании с DirectX. Моя проблема связана ни с тем, ни с другим.
Кто-нибудь может объяснить, что это на самом деле означает?
9 ответов
Вам нужно перейти в меню "Отладка" -> "Исключения", открыть "Помощники по управляемой отладке", найти LoaderLock и снять флажок
Общая идея блокировки загрузчика: система запускает код в DllMain внутри блокировки (как в синхронизации блокировки). Следовательно, выполнение нетривиального кода внутри DllMain "требует тупиковой ситуации", как описано здесь.
Вопрос в том, почему вы пытаетесь запустить код внутри DllMain? Крайне важно, чтобы этот код выполнялся в контексте DllMain, или вы можете порождать новый поток и запускать в нем код, а не ждать, пока код завершит выполнение внутри DllMain?
Я считаю, что проблема, в частности, с управляемым кодом, заключается в том, что запуск управляемого кода может включать загрузку CLR и тому подобное, и неизвестно, что там может произойти, что приведет к тупику... Я бы не прислушался к совету "отключить это предупреждение". "Если бы я был вами, потому что, скорее всего, вы обнаружите, что ваши приложения неожиданно зависают при некоторых сценариях.
ОБНОВЛЕНИЕ ДЛЯ.NET 4.0 И БОЛЕЕ ПОСЛЕДНИЕ РАМКИ
Это старый вопрос, который задавался во времена.Net 2.0, когда поддержка DLL-библиотек смешанного режима имела серьезные проблемы с инициализацией, склонные к случайным тупикам. Начиная с.Net 4.0, инициализация DLL смешанного режима изменилась. Теперь есть два отдельных этапа инициализации:
- Собственная инициализация, вызываемая в точке входа DLL, которая включает в себя собственную настройку времени выполнения C++ и выполнение вашего метода DllMain.
- Управляемая инициализация, выполняется автоматически загрузчиком системы.
Поскольку шаг № 2 выполняется вне блокировки загрузчика, взаимоблокировки отсутствуют. Детали описаны в разделе "Инициализация смешанных сборок".
Чтобы гарантировать, что ваша сборка смешанного режима может быть загружена из собственного исполняемого файла, единственное, что вам нужно проверить, - это то, что метод DllMain объявлен как собственный код. #pragma unmanaged
может помочь здесь:
#pragma unmanaged
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
... // your implementation here
}
Также важно, что любой код, который DllMain может вызывать прямо или косвенно, также неуправляем. Имеет смысл ограничить тип функциональности, используемой DllMain, чтобы вы могли отслеживать весь код, достижимый из DllMain, и убедиться, что он весь скомпилирован с #pragma unmanaged
,
Компилятор немного помогает, давая вам предупреждающий C4747, если он обнаруживает, что DllMain не объявлен как неуправляемый:
1> Generating Code...
1>E:\src\mixedmodedll\dllmain.cpp : warning C4747: Calling managed 'DllMain': Managed code may not be run under loader lock, including the DLL entrypoint and calls reached from the DLL entrypoint
Однако компилятор не будет генерировать никаких предупреждений, если DllMain косвенно вызовет какую-то другую управляемую функцию, поэтому вам нужно убедиться, что этого никогда не произойдет, иначе ваше приложение может случайно заблокироваться.
Напоминаем пользователям VS2017, что вам нужно отключить " помощник по исключениям " вместо " помощник по исключениям "(до VS2017), чтобы избежать ошибки блокировки загрузчика, для которой задан путь отладки -> Исключение. Просто побежал к этой проблеме и потратил 2 часа на поиски решений...
Нажмите ctr d+e, а затем - "Расширить узел управляемых помощников по отладке". Затем снимите флажок блокировки загрузчика.
Надеюсь, что это поможет вам.
Недавно я получил эту ошибку при создании экземпляра COM-объекта, написанного на собственном коде:
m_ComObject = Activator.CreateInstance(Type.GetTypeFromProgID("Fancy.McDancy"));
Это привело к описанной ошибке. "LoaderLock был обнаружен"- исключение было сгенерировано.
Я преодолел эту ошибку, создав экземпляр объекта в дополнительном потоке:
ThreadStart threadRef = new ThreadStart(delegate { m_ComObject = Activator.CreateInstance(Type.GetTypeFromProgID("Fancy.McDancy")); });
Thread myThread = new Thread(threadRef);
myThread.Start();
myThread.Join(); // for synchronization
Я создаю C++ CLR DLL (MSVS2015), которая должна выполнять вызовы в неуправляемую DLL и определять неуправляемый код. Я использую управляемый #pragma и неуправляемый #pragma, чтобы контролировать, в каком режиме он находится для данной области кода.
В моем случае я просто поставил #pragma неуправляемым перед моим DllMain(), и это решило проблему. Кажется, я думал, что мне нужна управляемая версия DllMain().
Эта проблема возникает из-за того, как отладчик в Visual Studio запускает управляемые приложения, использующие классы Microsoft Foundation 8.0 в одном или нескольких файлах DLL.
Внимательно прочитайте по адресу: http://msdn.microsoft.com/en-us/library/aa290048(vs.71).aspx
Путь настройки в моем экземпляре Visual Studio 2017: Отладка -> Windows -> Настройки исключений. "Окно" настроек исключений, появившееся в нижней вкладке группы (в отличие от отдельного окна), заняло у меня некоторое время, чтобы заметить это. Поиск "погрузчик".