GC.KeepAlive против использования - PullRequest
13 голосов
/ 11 марта 2009

В своей статье о предотвращении нескольких экземпляров приложения Майкл Ковингтон представляет этот код:

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) требуется, чтобы сборщик мусора не собирал мьютекс на ранней стадии, поскольку на него нет дополнительных ссылок.

Мой вопрос: будет ли перенос мьютекса в использование делать то же самое? То есть, следующее также помешает 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 ]

17 голосов
/ 11 марта 2009

Обертывание мьютекса в операторе using действительно предотвратит его сборку мусора, но также удалит его (он вызывает Dispose, а не Close) в конце (тогда как GC.KeepAlive не будет, очевидно).

Если конец метода действительно станет концом процесса, я не думаю, что это может иметь какое-либо практическое значение, которое вы используете - я предпочитаю утверждение using об общем принципе избавления от все, что реализует IDisposable.

Если мьютекс не был удален при выходе из процесса, я подозреваю, что его финализатор позаботится об этом - до тех пор, пока другие финализаторы не задержат поток финализации по истечении времени ожидания.

Если финализатор не позаботится об этом, я не знаю, заметит ли сама Windows, что процесс больше не может владеть мьютексом, учитывая, что он (процесс) больше не существует , Я подозреваю, что так и будет, но вам нужно проверить подробную документацию по Win32, чтобы точно знать.

5 голосов
/ 11 марта 2009

Использование using в данном случае лучше подходит, чем GC.KeepAlive. Вы не только хотите сохранить Mutex активным, пока приложение работает, вы также хотите, чтобы оно исчезло, как только вы выйдете из основного цикла.

Если вы просто оставите Mutex в подвешенном состоянии, не утилизируя его, может пройти некоторое время, прежде чем он будет завершен, в зависимости от того, сколько работы по очистке необходимо выполнить при закрытии приложения.

0 голосов
/ 24 апреля 2009

Я думаю, причина, по которой KeepAlive используется с названным Mutex, заключается в том, чтобы убедиться, что это НЕ мусор на ранних этапах. Шаблон C # using / Dispose не защищен от этого. Когда ссылка на объект больше не используется в области действия, среда выполнения может собирать ее до конца области. Это оптимизация.

...