获取互斥锁时如何避免竞争条件?

时间:2012-02-09 00:08:20

标签: c# .net mutex race-condition

我使用命名系统互斥来同步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之前有一个小窗口,其他应用程序可能已经获得了互斥锁。

避免这种竞争条件并使此代码更可靠的最佳方法是什么?

一位同事提到他在他的代码中使用了Win32 Platform SDK中的CreateMutex(另一个需要同步的进程)。但是,.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 个答案:

答案 0 :(得分:4)

有一个专门为此目的而设计的构造函数。来自docs

  

<强> createdNew
      键入: System.Boolean
  当此方法返回时,包含一个布尔值,如果创建了本地互斥锁(即,如果name为null或空字符串),或者创建了指定的命名系统互斥锁,则该值为true;如果已存在指定的命名系统互斥锁,则返回false。此参数未初始化传递。

相关问题