Search code examples
c#winformsmutexsingle-instance

Is using a Mutex to prevent multiple instances of the same program from running safe?


I'm using this code to prevent a second instance of my program from running at the same time, is it safe?

Mutex appSingleton = new System.Threading.Mutex(false, "MyAppSingleInstnceMutx");
if (appSingleton.WaitOne(0, false)) {
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new MainForm());
    appSingleton.Close();
} else {
    MessageBox.Show("Sorry, only one instance of MyApp is allowed.");
}

I'm worried that if something throws an exception and the app crashes that the Mutex will still be held. Is that true?


Solution

  • 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:

    1. Normal process startup.
    2. Second process starts up and aquires a handle to the mutex but is switched out before the WaitOne call.
    3. Process #1 is abruptly terminated. The mutex is not destroyed because process #2 has a handle. It is instead set to an abandoned state.
    4. The second process starts running again and gets an AbanonedMutexException.