代码之家  ›  专栏  ›  技术社区  ›  Jim Mischel

gc.keepalive与using

  •  13
  • Jim Mischel  · 技术社区  · 15 年前

    在他的 article about preventing multiple instances 在应用程序中,Michael Covington提供了以下代码:

    static void Main()                  // args are OK here, of course
    {
        bool ok;
        m = new System.Threading.Mutex(true, "YourNameHere", out ok);
    
        if (! ok)
        {
            MessageBox.Show("Another instance is already running.");
            return;
        }
    
        Application.Run(new Form1());   // or whatever was there
    
        GC.KeepAlive(m);                // important!
    }
    

    他解释说,gc.keepalive(m)是防止垃圾收集器过早收集互斥体所必需的,因为没有对它的附加引用。

    我的问题是:用using包装互斥体会做同样的事情吗?也就是说,下面还会阻止GC从我下面拉出地毯吗?

    static void Main()                  // args are OK here, of course
    {
        bool ok;
        using (var m = new System.Threading.Mutex(true, "YourNameHere", out ok))
        {
            if (! ok)
            {
                MessageBox.Show("Another instance is already running.");
                return;
            }
    
            Application.Run(new Form1());   // or whatever was there
        }
    }
    

    我的直觉反应是使用是可行的,因为使用(应该是)等同于:

    Mutex m = new System.Threading.Mutex(true, "YourNameHere", out ok);
    try
    {
        // do stuff here
    }
    finally
    {
        m.Close();
    }
    

    我认为m.close()足够向JIT编译器发出信号,表示存在另一个引用,从而防止过早的垃圾收集。

    3 回复  |  直到 15 年前
        1
  •  17
  •   Jon Skeet    15 年前

    将互斥体包装在 using 语句确实会阻止垃圾收集,但会 处理它(它调用 Dispose 不是 Close )最后(鉴于 GC.KeepAlive 显然不会)。

    如果方法的结尾真的会是过程的结尾,我相信它不会对您使用的方法产生任何实际的影响-我更喜欢 使用 关于处置任何实施的物品的一般原则的声明 IDisposable .

    如果互斥体在进程退出时没有被释放,我怀疑它的终结器会处理它-只要其他终结器不会在超时后占用终结线程。

    如果终结器不处理它,我不知道Windows本身是否会注意到进程可能不再拥有互斥体,因为它(进程)不再存在。我怀疑会的,但您必须检查详细的win32文档才能确定。

        2
  •  5
  •   Guffa    15 年前

    使用 using 在这种情况下似乎比使用 GC.KeepAlive . 你不仅想保留 Mutex 只要应用程序正在运行,您也希望它在退出主循环后立即消失。

    如果你离开 互斥 挂起而不处理它,根据应用程序关闭时需要做多少清理工作,可能需要一段时间才能完成。

        3
  •  -2
  •   Tim    15 年前

    我认为keepalive与命名的互斥体一起使用的原因是为了确保它不会被早期垃圾收集。C使用/处置模式不受保护。当对象引用不再在作用域内使用时,运行时可能会在作用域结束之前收集它。这是一个优化。