我最近将.NET NLog日志记录组件集成到我们的一个应用程序中,这些应用程序纯粹是在非托管代码(在Visual Studio 6中编译的C ++和VB6组件)中开发的。我们有一堆C ++应用程序通过COM接口与NLog通信。
目前一切正常但我注意到在程序终止期间弹出以下消息(在输出窗口中调试VS6中的C ++组件;如果在IDE中调试NLog,则通过VS 2005调试NLog):
检测到LoaderLock消息: 在OS中尝试托管执行 装载机锁。不要试图跑 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对象的引用,并在每次要写入日志文件时释放它...而不是最优雅的解决方案)
答案 0 :(得分:6)
忽略此消息绝对不安全。如果您点击此消息,您几乎肯定会创建一个真正的加载程序锁定策略违规。这是一个非常严重的错误,可能会导致程序中出现不可预测的行为(包括死锁)。
避免这种情况的最佳方法是不直接或间接访问DLL main中的任何其他.Net对象/函数。对于您的情况,最好使用不同的缓存策略。也许创建一个ref计数对象来保存.Net引用。这样,在调用DllMain进行卸载之前将释放该对象(在销毁所有对象之前无法卸载dll)。
答案 1 :(得分:2)
不要忽视。我在启动使用非托管C ++ DLL的C#应用程序时遇到了LoaderLock问题。在这种情况下,一些DLL代码(从Linux移植)具有在加载期间初始化时访问文件的静态。清理完静态后,修复了LoaderLock问题。以类似的方式,如果你有清理过程中访问文件的C / C ++静态,这可能会对你的LoaderLock有所帮助。