#c_sharp
Нужно, с одной стороны, обеспечить запуск единственного экземпляра приложения, с другой - в тестах надо имитировать запуск и выключение приложения. Пишу соответствующие методы: public static class Client { private static Mutex mutex; public static void Start() { var isSingle = false; mutex = new Mutex(false, guid, out isSingle); if (!isSingle) { Log.Add("Программа уже запущена."); Environment.Exit(1); } } public static void Close() { if (mutex != null && !mutex.SafeWaitHandle.IsClosed) { Log.Add("Wait mutex..."); mutex.WaitOne(); mutex.ReleaseMutex(); mutex.Close(); } } } Если создание и проверка в целом выглядят понятно, то вот с закрытием явные проблемы. По синтаксису хотелось вызвать просто ReleaseMutex, ему потребовался WaitOne, а потом оказалось, что ReleaseMutex не закрывает хендл и при следущем тесте старт уже невозможен, для чего пришлось добавлять ещё и Close(). Вопрос - так и надо делать или есть варианты проще?
Ответы
Ответ 1
Вы пытаетесь использовать сразу два разных свойства мьютекса: Уникальность именнованного мьютекса в системе Возможность захватить его только одному клиенту одновременно Первое свойство характерно не только для мьютексов, но для всех глобальных объектов синхронизации. Суть его в том, что в системе может существовать только один объект синхронизации с определенным именем. Попытка создать такой же объект откроет уже существующий (созданный в другом процессе), но при этом явно вам на это укажет - возвратом параметраcreatedNew == false. Мьютекс существует до тех пор, пока его хэндл не будет закрыт во всех процессах. Т.е. createdNew (ваш isSingle) будет выставлен в false в случае, если такой мьютекс уже где-то (в другом экземпляре приложения) существует. Т.е. сам по себе механизм предотвращения повторного запуска опирается исключительно на свойство единственности существования именованного Mutex, а не на возможность эксклюзивно его захватить. Методы WaitOne, ReleaseMutex и первый параметр конструктора - initiallyOwned используются для эксклюзивного захвата, и в вашем случае совершенно не нужны. Минимальный код в вашем случае выглядит так: public static class Client { private static Mutex mutex; public static void Start() { var createdNew = false; mutex = new Mutex(false, "someid", out createdNew); if (!createdNew) { Console.WriteLine("Программа уже запущена."); Environment.Exit(1); } } public static void Close() { if (mutex != null && !mutex.SafeWaitHandle.IsClosed) { Console.WriteLine("Close handle"); mutex.Close(); } } } Чтобы проверить, что сам по себе факт того, что вы используете именно Mutex, не влияет на результат, можете попробовать заменить его на что-то другое, например семафор с максимальным лимитом в 100: new Semaphore(0, 100, "someid", out createdNew) В отличии от мьютекса, его могут захватить до 100 раз. Но, как и в случае мьютекса, сама возможность захвата не используется - и он точно так же будет предотвращать запуск второго экземпляра - за счет уникальности имени.
Комментариев нет:
Отправить комментарий