2009-01-29 126 views
2

我最近將.NET NLog日誌記錄組件集成到我們的應用程序中,這些應用程序完全是在非託管代碼(在Visual Studio 6中編譯的C++和VB6組件)開發的。我們有一堆C++應用程序通過COM接口與NLog交談。程序終止時發生LoaderLock錯誤

目前一切正常,但我注意到在程序終止期間彈出以下消息(如果在VS6中調試C++組件,則在輸出窗口中;如果通過VS 2005調試NLog,則在IDE中作爲提示) :

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引用的釋放(我保持到NLOG對象的引用在我的C++類之一避免每次都要實例化和釋放),這會導致此警告彈出。

我的問題:這是安全的忽略?如果不是,什麼是一個好的解決方法? (我能想到的最好的辦法是實例化對該NLog對象的引用,並在每次我要寫入日誌文件時釋放它;不是最優雅的解決方案)

回答

6

這是絕對不安全的忽略此消息。如果你點擊這個消息,你幾乎肯定會創建一個真正的加載程序鎖定策略違規。這是一個非常嚴重的錯誤,可能會導致程序中出現不可預知的行爲(包括死鎖)。

避免這種情況的最佳方法是不直接或間接訪問任何其他.Net對象/函數。對於你的情況,最好使用不同的緩存策略。也許創建一個引用計數對象來保存.Net引用。這樣,在DllMain被調用卸載之前,對象將被釋放(在所有對象被銷燬之前,dll不能被卸載)。

2

不要忽視。我在啓動使用非託管C++ DLL的C#應用​​程序時遇到LoaderLock問題。在這種情況下,某些DLL代碼(從Linux移植)具有在加載期間在初始化時訪問文件的靜態內容。一旦靜態清理完畢,LoaderLock問題就解決了。以類似的方式,如果您有清理期間訪問文件的C/C++靜態內容,這可能會對LoaderLock有所貢獻。

+0

從非託管C++ DLL訪問文件如何導致託管C#代碼執行? – 2009-04-23 11:29:40