I am using a named system mutex to synchronise 2 processes. This is how I am currently acquiring a mutex within my application:
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 will throw an exception if the named system mutex with MutexName doesn’t exist, allowing my application to create it.
However, there seems to be a race condition here – if OpenExisting throws, there is a small window before the call to new Mutex where the other application may have acquired the mutex.
What is the best way to avoid this race condition and make this code more reliable?
A colleague mentioned that he was using CreateMutex from the Win32 Platform SDK in his code (the other process which needs to be synchronised). This doesn’t seem to be natively supported by the .NET Framework, however. So I’m not sure it’s the best solution for my code.
Update
Based on the answer from @David Schwartz, here is my new code:
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;
}
There’s a constructor specifically designed for this purpose. From the docs: