GC.KeepAlive против использования
В статье о предотвращении нескольких экземпляров приложения 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) требуется, чтобы сборщик мусора не собирал мьютекс раньше, так как дополнительных ссылок на него нет.
Мой вопрос: обертывание мьютекса при использовании делает то же самое? То есть, будет ли также предотвращено вытеснение 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, что есть еще одна ссылка, тем самым предотвращая преждевременную сбор мусора.
Ответы
Ответ 1
Обтекание мьютекса в инструкции using
действительно предотвратит его сбор мусора, но также избавит его (он вызывает Dispose
, а не Close
) в конце (тогда как GC.KeepAlive
не будет, очевидно).
Если конец метода действительно станет завершением процесса, я не верю, что это может привести к какой-либо практической разнице, которую вы используете. Я предпочитаю инструкцию using
по общему принципу утилизации все, что реализует IDisposable
.
Если мьютекс не был удален, когда процесс завершается, я подозреваю, что его финализатор позаботится об этом - до тех пор, пока другие финализаторы не заведут поток финализации за пределами своего таймаута.
Если финализатор не позаботится об этом, я не знаю, увидит ли сама Windows, что процесс больше не может владеть мьютексом, учитывая, что он (процесс) больше не существует, Я подозреваю, что это произойдет, но вам нужно будет проверить подробную документацию Win32, чтобы точно знать.
Ответ 2
Использование using
кажется более подходящим в этом случае, чем использование GC.KeepAlive
. Вы не только хотите сохранить Mutex
до тех пор, пока приложение запущено, вы также хотите, чтобы он ушел, как только вы выходите из основного цикла.
Если вы просто оставите винт Mutex
без его удаления, может быть некоторое время до его завершения, в зависимости от того, сколько работы по очистке должно выполняться, когда приложение закрывается.
Ответ 3
Я думаю, что причина, по которой KeepAlive используется с именованным Mutex, заключается в том, чтобы убедиться, что это не мусор, собранный раньше. Образец С#, использующий /Dispose, не защищен от этого. Когда ссылка на объект больше не используется в пределах области видимости, среда выполнения может собирать ее до конца области. Это оптимизация.