15

在他关于防止应用程序的多个实例的文章中,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
    }
}

我的直觉反应是 using 会起作用,因为 using (应该)相当于:

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

而且我认为 m.Close() 足以向 JIT 编译器发出另一个引用的信号,从而防止过早的垃圾收集。

4

3 回答 3

19

将互斥锁包装在using语句中确实可以防止它被垃圾收集,但也会最后处理它(它调用Dispose, not Close)(而GC.KeepAlive显然不会)。

如果方法的结束真的会成为过程的结束,我认为它不会对您使用的任何实际差异产生任何影响 - 我更喜欢using关于处置任何实施的一般原则的陈述IDisposable

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

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

于 2009-03-11T18:00:32.750 回答
5

在这种情况下,使用using似乎比使用更适合GC.KeepAlive。您不仅希望Mutex在应用程序运行时保持活动状态,还希望它在退出主循环后立即消失。

如果您只是将其Mutex挂起而不进行处理,则可能需要一段时间才能完成,具体取决于应用程序关闭时需要执行的清理工作量。

于 2009-03-11T18:17:35.390 回答
-2

我认为 KeepAlive 与命名的 Mutex 一起使用的原因是确保它不会及早被垃圾收集。C# using / Dispose 模式不适用于防止这种情况。当对象引用不再在范围内使用时,运行时可能会在范围结束之前收集它。这是一个优化。

于 2009-04-24T19:21:22.593 回答