Question

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?

Was it helpful?

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.

OTHER TIPS

It is more usual and convenient to use Windows events for this purpose. E.g.

static EventWaitHandle s_event ;

bool created ;
s_event = new EventWaitHandle (false, 
    EventResetMode.ManualReset, "my program#startup", out created) ;
if (created) Launch () ;
else         Exit   () ;

When your process exits or terminates, Windows will close the event for you, and destroy it if no open handles remain.

Added: to manage sessions, use Local\ and Global\ prefixes for the event (or mutex) name. If your application is per-user, just append a suitably mangled logged-on user's name to the event name.

You can use a mutex, but first make sure that this is really what you want.

Because "avoiding multiple instances" is not clearly defined. It can mean

  1. Avoiding multiple instances started in the same user session, no matter how many desktops that user session has, but allowing multiple instances to run concurrently for different user sessions.
  2. Avoiding multiple instances started in the same desktop, but allowing multiple instances to run as long as each one is in a separate desktop.
  3. Avoiding multiple instances started for the same user account, no matter how many desktops or sessions running under this account exist, but allowing multiple instances to run concurrently for sessions running under a different user account.
  4. Avoiding multiple instances started on the same machine. This means that no matter how many desktops are used by an arbitrary number of users, there can be at most one instance of the program running.

By using a mutex, you're basically using the define number 4.

I use this method, I believe it to be safe because the Mutex is destroyed if no long held by any application (and applications are terminated if if they can't initially create the Mutext). This may or may not work identically in 'AppDomain-processes' (see link at bottom):

// Make sure that appMutex has the lifetime of the code to guard --
// you must keep it from being collected (and the finalizer called, which
// will release the mutex, which is not good here!).
// You can also poke the mutex later.
Mutex appMutex;

// In some startup/initialization code
bool createdNew;
appMutex = new Mutex(true, "mutexname", out createdNew);
if (!createdNew) {
  // The mutex already existed - exit application.
  // Windows will release the resources for the process and the
  // mutex will go away when no process has it open.
  // Processes are much more cleaned-up after than threads :)
} else {
  // win \o/
}

The above suffers from from notes in other answers/comments about malicious programs being able to sit on a mutex. Not a concern here. Also, unprefixed mutex created in "Local" space. It's probably the-right-thing here.

See: http://ayende.com/Blog/archive/2008/02/28/The-mysterious-life-of-mutexes.aspx -- comes with Jon Skeet ;-)

On Windows, terminating a process has the following results:

  • Any remaining threads in the process are marked for termination.
  • Any resources allocated by the process are freed.
  • All kernel objects are closed.
  • The process code is removed from memory.
  • The process exit code is set.
  • The process object is signaled.

Mutex objects are kernel objects, so any held by a process are closed when the process terminates (in Windows anyway).

But, note the following bit from the CreateMutex() docs:

If you are using a named mutex to limit your application to a single instance, a malicious user can create this mutex before you do and prevent your application from starting.

Yes, it's safe, I'd suggest the following pattern, because you need to make sure that the Mutex gets always released.

using( Mutex mutex = new Mutex( false, "mutex name" ) )
{
    if( !mutex.WaitOne( 0, true ) )
    {
        MessageBox.Show("Unable to run multiple instances of this program.",
                        "Error",  
                        MessageBoxButtons.OK, 
                        MessageBoxIcon.Error);
    }
    else
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new MainForm());                  
    }
}

Here's the code snippet

public enum ApplicationSingleInstanceMode
{
    CurrentUserSession,
    AllSessionsOfCurrentUser,
    Pc
}

public class ApplicationSingleInstancePerUser: IDisposable
{
    private readonly EventWaitHandle _event;

    /// <summary>
    /// Shows if the current instance of ghost is the first
    /// </summary>
    public bool FirstInstance { get; private set; }

    /// <summary>
    /// Initializes 
    /// </summary>
    /// <param name="applicationName">The application name</param>
    /// <param name="mode">The single mode</param>
    public ApplicationSingleInstancePerUser(string applicationName, ApplicationSingleInstanceMode mode = ApplicationSingleInstanceMode.CurrentUserSession)
    {
        string name;
        if (mode == ApplicationSingleInstanceMode.CurrentUserSession)
            name = $"Local\\{applicationName}";
        else if (mode == ApplicationSingleInstanceMode.AllSessionsOfCurrentUser)
            name = $"Global\\{applicationName}{Environment.UserDomainName}";
        else
            name = $"Global\\{applicationName}";

        try
        {
            bool created;
            _event = new EventWaitHandle(false, EventResetMode.ManualReset, name, out created);
            FirstInstance = created;
        }
        catch
        {
        }
    }

    public void Dispose()
    {
        _event.Dispose();
    }
}

If you want to use a mutex-based approach, you should really use a local mutex to restrict the approach to just the curent user's login session. And also note the other important caveat in that link about robust resource disposal with the mutex approach.

One caveat is that a mutex-based approach doesn't allow you to activate the first instance of the app when a user tries to start a second instance.

An alternative is to PInvoke to FindWindow followed by SetForegroundWindow on the first instance. Another alternative is to check for your process by name:

Process[] processes = Process.GetProcessesByName("MyApp");
if (processes.Length != 1)
{
    return;
} 

Both of these latter alternatives have a hypothetical race condition where two instances of the app could be started simultaneously and then detect each other. This is unlikely to happen in practice - in fact, during testing I couldn't make it happen.

Another issue with these two latter alternatives is that they won't work when using Terminal Services.

Use app with timeout and security settings with avoiding AbandonedMutexException. I used my custom class:

private class SingleAppMutexControl : IDisposable
    {
        private readonly Mutex _mutex;
        private readonly bool _hasHandle;

        public SingleAppMutexControl(string appGuid, int waitmillisecondsTimeout = 5000)
        {
            bool createdNew;
            var allowEveryoneRule = new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null),
                MutexRights.FullControl, AccessControlType.Allow);
            var securitySettings = new MutexSecurity();
            securitySettings.AddAccessRule(allowEveryoneRule);
            _mutex = new Mutex(false, "Global\\" + appGuid, out createdNew, securitySettings);
            _hasHandle = false;
            try
            {
                _hasHandle = _mutex.WaitOne(waitmillisecondsTimeout, false);
                if (_hasHandle == false)
                    throw new System.TimeoutException();
            }
            catch (AbandonedMutexException)
            {
                _hasHandle = true;
            }
        }

        public void Dispose()
        {
            if (_mutex != null)
            {
                if (_hasHandle)
                    _mutex.ReleaseMutex();
                _mutex.Dispose();
            }
        }
    }

and use it:

    private static void Main(string[] args)
    {
        try
        {
            const string appguid = "{xxxxxxxx-xxxxxxxx}";
            using (new SingleAppMutexControl(appguid))
            {
                //run main app
                Console.ReadLine();
            }
        }
        catch (System.TimeoutException)
        {
            Log.Warn("Application already runned");
        }
        catch (Exception ex)
        {
            Log.Fatal(ex, "Fatal Error on running");
        }
    }

Here is how I have approached this

In the Program class: 1. Get a System.Diagnostics.Process of YOUR application using Process.GetCurrentProcess() 2. Step through the collection of open processes with the current name of your application using Process.GetProcessesByName(thisProcess.ProcessName) 3. Check each process.Id against thisProcess.Id and if an instance is already opened then at least 1 will match name but not Id, otherwise continue opening instance

using System.Diagnostics;

.....    

static void Main()
{
   Process thisProcess = Process.GetCurrentProcess();
   foreach(Process p in Process.GetProcessesByName(thisProcess.ProcessName))
   {
      if(p.Id != thisProcess.Id)
      {
         // Do whatever u want here to alert user to multiple instance
         return;
      }
   }
   // Continue on with opening application

A nice touch to finish this off would be to present the already opened instance to the user, chances are they didn't know it was open, so let's show them it was. To do this I use User32.dll to Broadcast a message into the Windows messaging loop, a custom message, and I have my app listen for it in the WndProc method, and if it gets this message, it presents itself to the user, Form.Show() or whatnot

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top