Как избежать состояния гонки при приобретении мьютекса? - PullRequest
3 голосов
/ 09 февраля 2012

Я использую именованный системный мьютекс для синхронизации 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 бросает, перед вызовом на new Mutex появляется небольшое окно, где другое приложение могло получить мьютекс.

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

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


Обновление

Основываясь на ответе @David Schwartz, вот мой новый код:

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;
}

1 Ответ

4 голосов
/ 09 февраля 2012

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

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

...