2012-02-09 3 views
3

Я использую именованный системный мьютекс, чтобы синхронизировать 2 процесса. Это, как я в настоящее время приобретает мьютекс в моем приложении:Как избежать состояния гонки при приобретении мьютекса?

using System.Threading; 

public static bool AcquireMutex() 
{ 
    // Protect against double acquisitions 
    if (MyMutex != null) 
    { 
     throw new ApplicationException("Failed to acquire mutex"); 
    } 

    try 
    { 
     // See if a named system mutex has already been created - if it has, 
     // wait a short amount of time for its release. 
     MyMutex = Mutex.OpenExisting(MutexName); 
     if (!MyMutex.WaitOne(TimeSpan.FromSeconds(2), false)) 
     { 
      // MyMutex still being held 
      MyMutex = null; 
      return false; 
     } 
    } 
    catch 
    { 
     // MyMutex doesn't exist so create it 
     MyMutex = new Mutex(true, MutexName); 
    } 

    return true; 
} 

OpenExisting сгенерирует исключение, если названная система взаимной блокировки с MutexName не существует, что позволяет мое приложение, чтобы создать его.

Однако, похоже, здесь есть состояние гонки - если OpenExisting выбрасывается, перед вызовом есть небольшое окно, где другое приложение, возможно, приобрело мьютекс.

Каков наилучший способ избежать этого состояния гонки и сделать этот код более надежным?

Коллега упоминает, что он использовал CreateMutex из SDK Win32 Platform в своем коде (другой процесс, который необходимо синхронизировать). Однако это, похоже, не поддерживается в основном .NET Framework. Поэтому я не уверен, что это лучшее решение для моего кода.


Update

На основании ответа от @David Шварца, вот мой новый код:

public static bool AcquireMutex() 
{ 
    // Protect against double acquisitions 
    if (MyMutex != null) 
    { 
     throw new ApplicationException("Failed to acquire mutex"); 
    } 

    bool createdNew; 
    MyMutex = new Mutex(true, MutexName, out createdNew); 
    if (createdNew) 
    { 
     // Mutex was created so ownership is guaranteed; no need to wait on it. 
     return true; 
    } 

    try 
    { 
     if (!MyMutex.WaitOne(TimeSpan.FromSeconds(2), false)) 
     { 
      MyMutex = null; 
      return false; 
     } 
    } 
    catch (AbandonedMutexException) 
    { 
     // Other application was aborted, which led to an abandoned mutex. 
     // This is fine, as we have still successfully acquired the mutex. 
    } 

    return true; 
} 
+0

Да, это не сработает. Вам нужно сделать один из процессов босса, тот, который его создает. Выберите один, как правило, первый. Если другой процесс не может открыть его, значит, что-то действительно не так. Он должен ждать. –

+0

@ Ханс - Я вносил изменения, основанные на ответе Дэвида Шварца: можете ли вы увидеть мой обновленный код и сообщить мне, если он выглядит правильно. – LeopardSkinPillBoxHat

+0

AbandonedMutexException вызывается только в том случае, если вы делаете что-то серьезно неправильно. Я бы не замолчил его, как в коде выше, но позвольте моему глобальному обработчику исключений зарегистрировать его для дальнейшего анализа. См. Https://msdn.microsoft.com/en-us/library/system.threading.abandonedmutexexception(v=vs.110).aspx –

ответ

4

Там в конструкторе, специально предназначенный для этой цели. Из docs:

createdNew
Тип: System.Boolean
Когда этот метод возвращается, содержит логическое значение, которое истинно, если локальный мьютекс был создан (то есть, если имя пустое или пустая строка) или если указан указанный именованный системный мьютекс; false, если указанный именованный системный мьютекс уже существует. Этот параметр передается неинициализированным.

+0

Спасибо за ответ - можете ли вы увидеть мой обновленный код в исходном вопросе, и дайте мне знать, если это будет выглядеть правильно. – LeopardSkinPillBoxHat