如何避免装载机锁定?

时间:2010-03-19 21:10:22

标签: c# managed-code

我们有一个使用程序集的托管应用程序。该程序集使用一些非托管C ++代码。

托管C ++代码在dll中,取决于其他几个dll。所有这些Dll都由此代码加载。 (我们首先加载ImageCore.dll所依赖的所有dll,因此我们可以判断哪些是缺失的,否则它只会显示为ImageCore.dll无法加载,并且日志文件不会提供任何关于原因的线索)。

class Interop
{
    private const int DONT_RESOLVE_DLL_REFERENCES = 1;
    private static log4net.ILog log = log4net.LogManager.GetLogger("Imagecore.NET");

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr LoadLibraryEx(string fileName, IntPtr dummy, int flags);
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr FreeLibrary(IntPtr hModule);

    static private String[] libs = { "log4cplus.dll", "yaz.dll", "zlib1.dll", "libxml2.dll" };

    public static void PreloadAssemblies()
    {
        for (int i=0; i < libs.Length; ++i) {
            String libname = libs[i];

            IntPtr hModule = LoadLibraryEx(libname, IntPtr.Zero, DONT_RESOLVE_DLL_REFERENCES);
            if(hModule == IntPtr.Zero) {
                log.Error("Unable to pre-load '" + libname + "'");
                throw new DllNotFoundException("Unable to pre-load '" + libname + "'");
            } else {
                FreeLibrary(hModule);
            }
        }

        IntPtr h = LoadLibraryEx("ImageCore.dll", IntPtr.Zero, 0);
        if (h == IntPtr.Zero) {
            throw new DllNotFoundException("Unable to pre-load ImageCore.dll");
        }
    }
}

此代码由

调用
public class ImageDoc : IDisposable {
    static ImageDoc()
    {
        ImageHawk.ImageCore.Utility.Interop.PreloadAssemblies();
    }
    ...
}

哪个是静态构造函数。

尽管我可以理解它,但只要我们尝试使用ImageDoc对象,就会加载包含该程序集的dll,并且作为该加载的一部分,将调用静态构造函数,从而导致其他几个DLL也加载。我想弄清楚的是,我们如何推迟加载这些DLL,以便我们不会因为静态构造函数而将smack dab运行到这个被踢出的加载器锁中。

通过查看:

,我把它拼凑在了一起
  1. http://social.msdn.microsoft.com/Forums/en-US/vsto/thread/dd192d7e-ce92-49ce-beef-3816c88e5a86
  2. http://msdn.microsoft.com/en-us/library/aa290048%28VS.71%29.aspx
  3. http://forums.devx.com/showthread.php?t=53529
  4. http://www.yoda.arachsys.com/csharp/beforefieldinit.html
  5. 但我似乎无法找到一种方法来加载这些外部DLL,而不会在类加载时发生。我想我需要从静态构造函数中获取这些LoadLibrary调用,但是不知道如何在需要它们之前调用它们(除了它在这里完成的方式)。我宁愿不必将这种dll知识放到每个使用这个程序集的应用程序中。 (而且我不确定那会解决这个问题......

    奇怪的是,异常只是在调试器中运行时才出现,而不是在调试器外运行时。

    如何设置加载这些DLL而不会遇到以下错误:

    LoadLibrary <- .NET loads the class from assembly dll 
    DllMain 
    LoadLibrary <- -Due to Static ctor 
    DllMain
    

1 个答案:

答案 0 :(得分:3)

LoaderLock是来自调试器的MDA(托管调试助手)警告。它告诉您可能是代码的问题。它只发生在调试器下运行时,因为正在进行MDA检查的调试器通知您在某些情况下会出现“可能”的死锁。

不幸的是,我无法帮助你。我对LoaderLock的体验是:(a)VS给你的是一个神秘的警告,但是很少有人支持你告诉你如何解决它,以及(b)我们的应用程序已经使用LoaderLock运行了4年关闭(在DirectX中,所以它甚至不在我们的代码中)并且它实际上从未引起过问题,除了每次我们在调试器下运行时都是烦人的麻烦。 YMMV当然。

(您可以在调试中禁用MDA - &gt;托管调试助手部分中的例外,但每次重置这些设置时,该死的MDA都会重新开启)