Я хочу убедиться, что это там, потому что это так трудно понять:
using System.Runtime.InteropServices; //GuidAttribute
using System.Reflection; //Assembly
using System.Threading; //Mutex
using System.Security.AccessControl; //MutexAccessRule
using System.Security.Principal; //SecurityIdentifier
static void Main(string[] args)
{
// get application GUID as defined in AssemblyInfo.cs
string appGuid =
((GuidAttribute)Assembly.GetExecutingAssembly().
GetCustomAttributes(typeof(GuidAttribute), false).
GetValue(0)).Value.ToString();
// unique id for global mutex - Global prefix means it is global to the machine
string mutexId = string.Format( "Global\\{{{0}}}", appGuid );
// Need a place to store a return value in Mutex() constructor call
bool createdNew;
// edited by Jeremy Wiebe to add example of setting up security for multi-user usage
// edited by 'Marc' to work also on localized systems (don't use just "Everyone")
var allowEveryoneRule =
new MutexAccessRule( new SecurityIdentifier( WellKnownSidType.WorldSid
, null)
, MutexRights.FullControl
, AccessControlType.Allow
);
var securitySettings = new MutexSecurity();
securitySettings.AddAccessRule(allowEveryoneRule);
// edited by MasonGZhwiti to prevent race condition on security settings via VanNguyen
using (var mutex = new Mutex(false, mutexId, out createdNew, securitySettings))
{
// edited by acidzombie24
var hasHandle = false;
try
{
try
{
// note, you may want to time out here instead of waiting forever
// edited by acidzombie24
// mutex.WaitOne(Timeout.Infinite, false);
hasHandle = mutex.WaitOne(5000, false);
if (hasHandle == false)
throw new TimeoutException("Timeout waiting for exclusive access");
}
catch (AbandonedMutexException)
{
// Log the fact that the mutex was abandoned in another process,
// it will still get acquired
hasHandle = true;
}
// Perform your work here.
}
finally
{
// edited by acidzombie24, added if statement
if(hasHandle)
mutex.ReleaseMutex();
}
}
}
using
чтобы проверитьcreatedNew
и добавитьmutex.Dispose()
внутрьfinally
. Я не могу объяснить это ясно (я не знаю причину) прямо сейчас, но я попал в ситуацию, когдаmutex.WaitOne
возвращалсяtrue
послеcreatedNew
сталfalse
(я получил мьютекс в текущем,AppDomain
а затем загрузил новыйAppDomain
и выполнил тот же код из внутри).exitContext = false
что-нибудь вmutex.WaitOne(5000, false)
? Похоже , что это может только вызвать Assert в CoreCLR , 2. Если кто интересно, вMutex
конструкторе «s, почемуinitiallyOwned
этоfalse
частично объясняется этой статье MSDN .Используя принятый ответ, я создаю вспомогательный класс, чтобы вы могли использовать его таким же образом, как и оператор Lock. Просто думал, что поделюсь.
Использование:
И вспомогательный класс:
источник
< 0
вместо<= 0
._mutex.Close()
вместо_mutex.Dispose()
метода Dispose работает для меня. Ошибка была вызвана попыткой избавиться от базового WaitHandle.Mutex.Close()
располагает основными ресурсами.В принятом ответе есть условие состязания, когда 2 процесса работают под двумя разными пользователями, пытаясь инициализировать мьютекс одновременно. После того, как первый процесс инициализирует мьютекс, если второй процесс пытается инициализировать мьютекс до того, как первый процесс установит правило доступа для всех, второй процесс создаст несанкционированное исключение.
Ниже приведен правильный ответ:
источник
Этот пример завершится через 5 секунд, если другой экземпляр уже запущен.
источник
Ни Mutex, ни WinApi CreateMutex () не работают для меня.
Альтернативное решение:
И то
SingleApplicationDetector
:Причина использования семафора вместо Mutex:
Ref: Semaphore.OpenExisting ()
источник
Semaphore.OpenExisting
иnew Semaphore
.Иногда обучение на примере помогает больше всего. Запустите это консольное приложение в трех разных консольных окнах. Вы увидите, что приложение, которое вы запустили первым, сначала получает мьютекс, а два других ждут своей очереди. Затем нажмите клавишу ввода в первом приложении, и вы увидите, что приложение 2 теперь продолжает работать, получая мьютекс, однако приложение 3 ожидает своей очереди. После нажатия кнопки ввода в приложении 2 вы увидите, что приложение 3 продолжается. Это иллюстрирует концепцию мьютекса, защищающего часть кода, которая будет выполняться только одним потоком (в данном случае процессом), например, запись в файл в качестве примера.
источник
Глобальный Mutex предназначен не только для того, чтобы иметь только один экземпляр приложения. Лично я предпочитаю использовать Microsoft.VisualBasic для обеспечения приложения с одним экземпляром, как описано в разделе Как правильно создать приложение WPF с одним экземпляром? (Дейл Раган ответ) ... Я обнаружил, что проще передать аргументы, полученные при запуске нового приложения, в исходное приложение с одним экземпляром.
Но что касается предыдущего кода в этой теме, я бы предпочел не создавать Mutex каждый раз, когда я хочу заблокировать его. Это может быть хорошо для одного экземпляра приложения, но при другом использовании оно кажется мне излишним.
Вот почему я предлагаю эту реализацию вместо:
Применение:
Mutex Global Wrapper:
Официант
источник
Решение (для WPF) без WaitOne, поскольку оно может вызвать исключение AbandonedMutexException. В этом решении используется конструктор Mutex, который возвращает логическое значение createNew, чтобы проверить, создан ли мьютекс. Он также использует GetType (). GUID, поэтому переименование исполняемого файла не допускает нескольких экземпляров.
Глобальный и локальный мьютекс см. В примечании: https://docs.microsoft.com/en-us/dotnet/api/system.threading.mutex?view=netframework-4.8
Поскольку Mutex реализует IDisposable, он освобождается автоматически, но для полноты вызова dispose:
Переместите все в базовый класс и добавьте allowEveryoneRule из принятого ответа. Также добавлен ReleaseMutex, хотя он не выглядит так, как будто он действительно нужен, потому что он автоматически выпускается ОС (что, если приложение завершится сбоем и никогда не вызовет ReleaseMutex, потребуется ли перезагрузка?).
источник