views:

386

answers:

2

I have recently integrated the .NET NLog logging component into one of our applications which developed purely in unmanaged code (C++ and VB6 components compiled in Visual Studio 6). We have a bunch of C++ application talking to NLog via a COM interface.

Everything is working fine at the moment but I do notice that the following message pops up (in the output window if debugging the C++ component in VS6; as a prompt in the IDE if debugging NLog via VS 2005) during program termination:

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.

The DllMain is as follows:

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
}

My guess is that _Module.Term(); now includes the releasing of some .NET references (I am keeping a reference to a NLog object in one of my C++ classes to avoid having to instantiate and release each time) which is causing this warning to pop up.

My question: is this safe to ignore? If it isn't, what is a good workaround? (the best I can think of is to instantiate a reference to that NLog object and release it every time I want to write to the log file...not the most elegant of solutions)

+4  A: 

It is most definitely not safe to ignore this message. If you hit this message, you've almost certainly created a real loader lock policy violation. This is a very serious error and can cause unpredictable behavior in a program (including deadlock).

The best way to avoid this is to not access any other .Net Objects/Functions directly or indirectly inside of DLL main. For your case, it's probably best to use a different cache policy. Perhaps create a ref counted object to hold the .Net reference. That way the object will be released before DllMain is called for unload (the dll can't be unloaded until all of your objects are destroyed).

JaredPar
+1  A: 

Don't ignore. I had a LoaderLock issue on startup of a C# app that used an unmanaged C++ DLL. In this case, some of the DLL code (ported from Linux) had statics that were accessing files on initialization during load. Once the statics were cleaned up, the LoaderLock issue was fixed. In a similar way, if you have C/C++ statics that access files during cleanup, this could be contributing to your LoaderLock.

Tim Butterfield
How does accessing files from an unmanaged C++ DLL cause managed C# code to be executed?
Wim Coenen
The C# code is running first and makes a call to a method exported by the unmanaged DLL. The first time the exported method is called, the DLL is loaded by .Net. It is during this load of the unmanaged DLL that the DLL cannot access files. But, the static variables in the DLL are initialized during the loading of the DLL. And, if their initialization accesses files, a LoaderLock error can result. The error appears to be thrown by the C# code that called the DLL method that loaded the DLL.
Tim Butterfield