关于C#:加载程序锁定错误

Loader lock error

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

我说错了

LoaderLock was detected Message:
Attempting managed execution inside OS
Loader lock. Do not attempt to run
managed code inside a DllMain or image
initialization function since doing so
can cause the application to hang.

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

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


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

http://goo.gl/TGAHV


加载程序锁定的一般思想:
系统在DllMain中的一个锁(如-同步锁)中运行代码。因此,在DllMain中运行非平凡的代码就是"寻求死锁",如此处所述。

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

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


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

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

  • 在DLL的入口点调用的本机初始化,包括本机C ++运行时设置和DllMain方法的执行。
  • 托管初始化,由系统加载程序自动执行。
  • 由于步骤2是在装载机锁之外执行的,因此没有死锁。有关详细信息,请参见"混合装配的初始化"。

    为了确保可以从本机可执行文件加载混合模式程序集,您需要检查的唯一事情是将DllMain方法声明为本机代码。 #pragma unmanaged可以帮助您:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #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
    2
    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间接调用其他托管函数,则编译器将不会生成任何警告,因此您需要确保该操作永远不会发生,否则您的应用程序可能会随机死锁。


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

    希望这会帮助你。


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


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

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


    我最近在创建用本机代码编写的COM对象的实例时遇到此错误:

    1
    m_ComObject = Activator.CreateInstance(Type.GetTypeFromProgID("Fancy.McDancy"));

    这导致了所描述的错误。"检测到LoaderLock"-引发异常。

    我通过在额外的线程中创建对象实例来克服了此错误:

    1
    2
    3
    4
    5
    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中的调试器在一个或多个DLL文件中运行使用Microsoft Foundation Classes 8.0版的托管应用程序的方式。

    在以下位置有详尽的阅读:http://msdn.microsoft.com/zh-cn/library/aa290048(vs.71).aspx


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


    推荐阅读