2

我最近将 .NET NLog 日志记录组件集成到我们的一个应用程序中,该应用程序完全使用非托管代码(在 Visual Studio 6 中编译的 C++ 和 VB6 组件)开发。我们有一堆 C++ 应用程序通过 COM 接口与 NLog 通信。

目前一切正常,但我注意到在程序终止期间弹出以下消息(如果在 VS6 中调试 C++ 组件,则在输出窗口中;如果通过 VS 2005 调试 NLog,则作为 IDE 中的提示):

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

DllMain 如下:

extern "C"
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
{
    if (dwReason == DLL_PROCESS_ATTACH)
    {
        _Module.Init(ObjectMap, hInstance);
        DisableThreadLibraryCalls(hInstance);
    }
    else if (dwReason == DLL_PROCESS_DETACH)
        _Module.Term();
    return TRUE;    // ok
}

我的猜测是,_Module.Term();现在包括释放一些 .NET 引用(我在我的一个 C++ 类中保留对 NLog 对象的引用,以避免每次都实例化和释放),这会导致弹出此警告。

我的问题:这可以安全忽略吗?如果不是,有什么好的解决方法?(我能想到的最好的方法是实例化对该 NLog 对象的引用,并在每次我想写入日志文件时释放它……这不是最优雅的解决方案)

4

2 回答 2

6

忽略此消息绝对是不安全的。如果您点击此消息,您几乎可以肯定创建了一个真正的加载程序锁定策略违规。这是一个非常严重的错误,可能会导致程序出现不可预知的行为(包括死锁)。

避免这种情况的最佳方法是不要直接或间接访问 DLL main 内的任何其他 .Net 对象/函数。对于您的情况,最好使用不同的缓存策略。也许创建一个引用计数对象来保存 .Net 引用。这样,对象将在调用 DllMain 进行卸载之前被释放(在所有对象都被销毁之前,无法卸载 dll)。

于 2009-01-29T04:57:35.027 回答
2

不要忽视。我在启动使用非托管 C++ DLL 的 C# 应用程序时遇到了 LoaderLock 问题。在这种情况下,一些 DLL 代码(从 Linux 移植)具有在加载期间在初始化时访问文件的静态。清理完静态数据后,LoaderLock 问题就得到了修复。以类似的方式,如果您有在清理期间访问文件的 C/C++ 静态变量,这可能会导致您的 LoaderLock。

于 2009-01-29T06:24:43.853 回答