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