Is using a Mutex to prevent multiple instances of the same program from running safe?
In general yes this will work. However the devil is in the details.
Firstly you want to close the mutex in a finally
block. Otherwise your process could abruptly terminate and leave it in a signaled state, like an exception. That would make it so that future process instances would not be able to start up.
Unfortunately though, even with a finally
block you must deal with the potential that a process will be terminated without freeing up the mutex. This can happen for instance if a user kills the process through TaskManager. There is a race condition in your code that would allow for a second process to get an AbandonedMutexException
in the WaitOne
call. You'll need a recovery strategy for this.
I encourage you to read up on the details of the Mutex class. Using it is not always simple.
Expanding upon the race condition possibility:
The following sequence of events can occur which would cause a second instance of the application to throw:
- Normal process startup.
- Second process starts up and aquires a handle to the mutex but is switched out before the
WaitOne
call. - Process #1 is abruptly terminated. The mutex is not destroyed because process #2 has a handle. It is instead set to an abandoned state.
- The second process starts running again and gets an
AbanonedMutexException
.
Mutex does not stop two instances of program from running at once
You can test the below code by running several instances simultaneously.
static void Main(string[] args)
{
using (var mutex = new Mutex(true, "UniqueSystemWideMutexName"))
{
//Timeout is set to zero so we don't block
if (!mutex.WaitOne(0))
{
Console.WriteLine("Program already running");
Console.ReadKey();
return;
}
Console.WriteLine("This is the only program running");
Console.ReadKey();
}
}
If you can't use Dispose
for whatever reason, which the using
block does for us, be sure to call ReleaseMutex
.
You can also use OpenExisting to check if the mutex has already been created, but it's not necessary for this simple use case.
Not able to prevent multiple instances of the same program from different users
You did not show the actual value of PREDEFINED_UNIQUE_ID
, but I'm guessing that it is not creating the mutex in the Global
kernel namespace, but in per-session namespaces instead. Using the Global
namespace is required for spanning user sessions:
The separate client session namespaces enable multiple clients to run the same applications without interfering with each other. For processes started under a client session, the system uses the session namespace by default. However, these processes can use the global namespace by prepending the "Global\" prefix to the object name. For example, the following code calls
CreateEvent
and creates an event object named CSAPP in the global namespace:CreateEvent( NULL, FALSE, FALSE, "Global\\CSAPP" );
...
Another use of the global namespace is for applications that use named objects to detect that there is already an instance of the application running in the system across all sessions. This named object must be created or opened in the global namespace instead of the per-session namespace. The more common case of running the application once per session is supported by default because the named object is created in a per session namespace.
UPDATE: you also need to handle the case where CreateMutex()
can't access a mutex in another session due to security permissions. You need to handle the case where GetLastError()
returns ERROR_ACCESS_DENIED
, which in of itself means the mutex exists.
Try something more like this:
#define PREDEFINED_UNIQUE_ID _T("Global\\MyUniqueMutexName");
m_hMutex = ::CreateMutex(NULL, FALSE, PREDEFINED_UNIQUE_ID);
// or: m_hMutex = ::CreateMutexEx(&sa, PREDEFINED_UNIQUE_ID, 0, SYNCHRONIZE);
DWORD dwErrorCode = ::GetLastError();
if ((m_hMutex) && (dwErrorCode == ERROR_ALREADY_EXISTS))
{
::CloseHandle(m_hMutex);
//in case the previous instance of APP is still in the process of closing
::Sleep(5*1000);
// consider using WaitForSingleObject() instead, in case the app takes less than 5 seconds to close...
m_hMutex = ::CreateMutex(NULL, FALSE, PREDEFINED_UNIQUE_ID);
// or: m_hMutex = ::CreateMutexEx(&sa, PREDEFINED_UNIQUE_ID, 0, SYNCHRONIZE);
dwErrorCode = ::GetLastError();
}
if (dwErrorCode != 0)
{
EndSplashWindow();
switch (dwErrorCode)
{
case ERROR_ALREADY_EXISTS:
case ERROR_ACCESS_DENIED:
AfxMessageBox( _T("An instance of APP is already running."), MB_OK | MB_ICONERROR | MB_SYSTEMMODAL );
break;
default:
AfxMessageBox( _T("Error checking if an instance of APP is already running."), MB_OK | MB_ICONERROR | MB_SYSTEMMODAL );
break;
}
return FALSE;
}
// OK to run now!
return TRUE;
Or, to minimize the chances of ERROR_ACCESS_DENIED
being reported, you can provide a NULL DACL to CreateMutex()
:
PSECURITY_DESCRIPTOR pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
if (!pSD)
{
EndSplashWindow();
AfxMessageBox( _T("Error allocating security descriptor."), MB_OK | MB_ICONERROR | MB_SYSTEMMODAL );
return FALSE;
}
if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
{
LocalFree(pSD);
EndSplashWindow();
AfxMessageBox( _T("Error initializing security descriptor."), MB_OK | MB_ICONERROR | MB_SYSTEMMODAL );
return FALSE;
}
if (!SetSecurityDescriptorDacl(pSD, TRUE, NULL, FALSE))
{
LocalFree(pSD);
EndSplashWindow();
AfxMessageBox( _T("Error setting access for security descriptor."), MB_OK | MB_ICONERROR | MB_SYSTEMMODAL );
return FALSE;
}
SECURITY_ATTRIBUTES sa = {};
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = pSD;
sa.bInheritHandle = FALSE;
m_hMutex = ::CreateMutex(&sa, FALSE, PREDEFINED_UNIQUE_ID);
...
LocalFree(pSD);
What is the safest way to prevent multiple instances of a program?
The safest way is to use the built-in support in .NET, WindowsFormsApplicationBase.IsSingleInstance property. Hard to guess if it is appropriate, you didn't make much effort describing your exact needs. And no, nothing changed in the past 5 years. – Hans Passant Jan 7 at 0:38
This was the best answer but Hans didn't submit it as an answer.
Run single instance of an application using Mutex
I did it this way once, I hope it helps:
bool createdNew;
Mutex m = new Mutex(true, "myApp", out createdNew);
if (!createdNew)
{
// myApp is already running...
MessageBox.Show("myApp is already running!", "Multiple Instances");
return;
}
Related Topics
Adding Your Own HTMLhelper in ASP.NET MVC 3
Convert JSON String to C# Object List
Catching "Maximum Request Length Exceeded"
Why Does Boolean.Tostring Output "True" and Not "True"
C# Pass by Value VS. Pass by Reference
Making Entity Class Closed for Changes
How to Check If Wpf Is Currently Executing in Design Mode or Not
Showing Difference Between Two Datetime Values in Hours
How to Call Base.Base.Method()
Open Image from File, Then Release Lock
Why Some Types Do Not Have Literal Modifiers
Localization of Displaynameattribute
Initializing C# Auto-Properties
How to Create an Animated Gif in .Net
Exclude Property from Serialization via Custom Attribute (JSON.Net)