装载机锁定错误


95

我通过在C#中编写代码来构建C ++ dll。

我说错了

检测到LoaderLock消息:尝试在OS Loader锁内进行托管执行。不要尝试在DllMain或图像初始化函数中运行托管代码,因为这样做可能导致应用程序挂起。

我尝试搜索该错误的确切含义,但是我写的文章毫无意义,主要是说这只是一个警告,我应该在Visual Studio中将其关闭。其他解决方案似乎是由于iTunes引起的,或者是使用DirectX进行编程时发生的此问题。我的问题与两个都不相关。

谁能解释,这实际上意味着什么?


我觉得与您一样,我遇到了同样的问题,最让我感到惊讶的是:我的dll甚至都不是托管代码,那么为什么/如何在(不存在的)DllMain上使用托管代码?
山姆

尝试在调试模式下查看数据集的内容时收到此警告。我正在使用c#,它以常规的Windows形式发生。
Soenhay

由于您无法找出原因(如您在最高答案中所述),我怀疑您正在加载的一个dll构成了犯罪。
John Thoits

Answers:


70

您需要转到菜单Debug-> Exceptions,打开Managed Debugging Assistants,找到LoaderLock并取消选中

http://goo.gl/TGAHV


21
是的,这是关闭警告的方法;但是即使在2年后,我仍未弄清楚发生这种情况的确切原因。
Devdatta Tengshe

2
这是我在VS 2012中打开一个旧项目时发生的事情
4imble

1
我与您在一起@Kohan我也打开了一个旧项目并收到错误消息。我已禁用了该异常,但想了解可以采取哪些措施来防止这种情况。
Pimenta

1
如果我以本机调试方式运行项目,并且所有异常均默认(全部重置),则调试窗口将显示<mda:msg xmlns:mda =“ schemas.microsoft.com/CLR/2004/10/mda ”> <!- -尝试在OS Loader锁中尝试托管执行。...--<mda:loaderLockMsg break =“ true” /> </ mda:msg> VS然后在CTOR序列中显示了多个断点。关闭LoaderLock设置无济于事。对我来说,我必须勾选最高级的MDA选项(对于所有MDA),然后取消勾选最高级的选项(对于没有MDA),然后进行build + run。这对我的同事不起作用。
GilesDMiddleton 2014年

17
要共享VS2015中的更新,现在需要转到Debug->Windows->Exception Settings。其余的与Managed Debugging Assistants \ LoaderLock
jxramos '16

52

加载程序锁的一般概念:系统在DllMain中的锁内运行代码(如-同步锁)。因此,运行里面的DllMain不平凡的代码是“要求死锁”,描述在这里

问题是,为什么要尝试在DllMain中运行代码?在DllMain的上下文中运行此代码是否至关重要,还是可以生成一个新线程并在其中运行代码,而不必等待代码在DllMain中完成执行?

我认为,托管代码的问题尤其在于,运行托管代码可能涉及加载CLR之类的东西,而且不知道在那里会发生什么情况,从而导致死锁……我不会听从“禁用此警告”的建议。 “如果我是您,因为很有可能您会发现在某些情况下应用程序意外挂起。


4
我正在研究Direct3D应用程序。这是一个EXE。但是,我仍然看到此错误。任何想法如何最好地解决此问题?
Agnel Kurian

18

.NET 4.0和更多最新框架的更新

这是在.Net 2.0时代提出的一个古老问题,当时对混合模式DLL的支持存在严重的初始化问题,容易出现随机死锁。从.Net 4.0开始,混合模式DLL的初始化已更改。现在有两个单独的初始化阶段:

  1. 在DLL的入口点调用的本机初始化,包括本机C ++运行时设置和DllMain方法的执行。
  2. 托管初始化,由系统加载程序自动执行。

由于步骤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

如果编译器检测到未将DllMain声明为不受管理,则可以通过警告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间接调用其他托管函数,则编译器不会生成任何警告,因此您需要确保该操作永远不会发生,否则您的应用程序可能会随机死锁。


6

按ctr d + e,然后按“扩展托管调试助手”节点。然后取消选中LoaderLock。

希望这会帮助你。


快捷键是alt + d + x
Narayan

3
快捷方式实际上取决于您在首次运行时指定使用的配置。C#快捷方式布局为(Ctrl + D,E)。(您也可以在选项->环境->键盘中为该功能分配任何组合键。)
Adam LS

5

请提醒那些VS2017用户,您需要禁用“ exception helper ”而不是“ exception assistant ”(在VS2017之前),以防止加载程序锁定错误,其设置路径为Debug-> Exception。刚遇到这个问题并浪费了2个小时来寻找解决方案...


我在“调试”下没有“异常”。我有VS2017社区15.8.4
亚历克斯(Alex)

@Alex,检查
Debug-> Windows-

4

我最近在创建用本机代码编写的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

该错误可能发生在Remotable对象(MarshalByRefObject)上,而该解决方案不适用于这些对象。
Matthieu

3

我正在构建一个C ++ CLR DLL(MSVS2015),它必须对非托管DLL进行调用并定义非托管代码。我使用#pragma托管和#pragma托管来控制代码给定区域的模式。

就我而言,我只是将#pragma不受管理地放在DllMain()的前面,这解决了问题。似乎在想我想要DllMain()的托管版本。



2

我的Visual Studio 2017实例中的设置路径是Debug-> Windows-> Exception Settings。异常设置“窗口”显示在底部的选项卡组中(与单独的窗口相对),我花了一段时间才注意到它。搜索“加载程序”。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.