装载机locking错误
我正在build立在C ++的DLL,通过在C#中编写代码。
我得到一个错误,说
检测到LoaderLock消息:试图在OS Loader锁内进行托pipe执行。 不要试图在DllMain或图像初始化函数中运行托pipe代码,因为这样做会导致应用程序挂起。
我尝试着去查找这个错误究竟意味着什么,但是我正在绘制一些没有意义的文章,主要是说这只是一个警告,我应该在Visual Studio中closures它。 其他解决scheme似乎是由于iTunes,或使用DirectX编程时发生此问题。 我的问题是不相连的。
谁能解释一下,这究竟意味着什么?
你需要进入菜单Debug – > Exceptions,打开Managed Debugging Assistants,findLoaderLock并取消选中
加载器locking的一般概念:系统在锁内部运行DllMain中的代码(作为同步锁)。 因此,在DllMain中运行非平凡的代码是“要求死锁”,如此处所述。
问题是,你为什么要在DllMain中运行代码? 这段代码在DllMain的上下文中运行至关重要,或者您可以产生一个新的线程并在其中运行代码,而不是等待代码在DllMain中完成执行?
我相信,与pipe理代码的具体问题是,运行托pipe代码可能涉及加载CLR等类似的,不知道会发生什么会导致死锁…我不会听从“禁用此警告“如果我是你,因为很可能你会发现你的应用程序在某些情况下意外挂起。
按ctr d + e然后取消pipe理的debugging助手节点。 然后取消选中LoaderLock。
希望这会帮助你。
.NET 4.0的更新和更新的框架
在.Net 2.0时,这是一个古老的问题,当支持混合模式的DLL有严重的初始化问题,容易产生随机死锁。 从.Net 4.0开始,混合模式DLL的初始化已经改变。 现在有两个独立的初始化阶段:
- 本地初始化,在DLL入口点处调用,其中包括本机C ++运行时设置和执行DllMain方法。
- pipe理初始化,由系统加载程序自动执行。
由于在装载程序锁外执行步骤#2,所以没有死锁。 有关详细信息,请参阅混合assembly的初始化 。
要确保您的混合模式程序集可以从本机可执行程序加载,唯一需要检查的是DllMain方法被声明为本机代码。 #pragma unmanaged
可以在这里帮助:
#pragma unmanaged BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { ... // your implementation here }
DllMain可能直接或间接调用的任何代码也是非托pipe的也是很重要的。 限制DllMain使用的function的types是有意义的,因此您可以跟踪所有可从DllMain访问的代码,并确保它是使用#pragma unmanaged
编译的。
如果编译器检测到DllMain没有被声明为非托pipe,则通过给C4747提供警告来帮助编译器:
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间接调用其他托pipe函数,编译器不会产生任何警告,所以您需要确保永不发生,否则您的应用程序可能会随机死锁。
我最近在创build用本地代码编写的COM对象的实例时遇到了这个错误:
m_ComObject = Activator.CreateInstance(Type.GetTypeFromProgID("Fancy.McDancy"));
这导致了所描述的错误。 “LoaderLock被检测到”-Exception被抛出。
我通过在一个额外的线程中创build对象实例克服了这个错误:
ThreadStart threadRef = new ThreadStart(delegate { m_ComObject = Activator.CreateInstance(Type.GetTypeFromProgID("Fancy.McDancy")); }); Thread myThread = new Thread(threadRef); myThread.Start(); myThread.Join(); // for synchronization
发生此问题的原因在于Visual Studio中的debugging器运行在一个或多个DLL文件中使用Microsoft基础类版本8.0的托pipe应用程序的方式。
请仔细阅读: http : //msdn.microsoft.com/en-us/library/aa290048(vs.71).aspx
我正在构build一个C ++ CLR DLL(MSVS2015),它必须调用非托pipeDLL并定义非托pipe代码。 我使用#pragma managed和#pragma unmanaged来控制代码的给定区域所处的模式。
在我的情况下,我只是把#pragma unmanaged在我的DllMain()前,这解决了这个问题。 这似乎是想我想要的DllMain()的pipe理版本。