2

I create a mutex within the OnStartup Method of a WPF app. The mutex is not used anywhere else in the program, its only purpose is to prevent certain programs from running concurrently. How can I release this mutex when the application closes?

According to the documentation, mutex.ReleaseMutex() must be called from the same thread that created the mutex. However this presents a problem, since I do not control the thread that calls OnStartup().

Suppose my OnStartup method looks like this:

public partial class App : Application
{
    private Mutex mutex;
    private bool hasHandle = false;

    protected override void OnStartup(StartupEventArgs e)
    {
        bool createdNew;
        mutex = new Mutex(false, @"Global\XYZ", out createdNew);
        try
        {
             hasHandle = mutex.WaitOne(5000, false);
             if (!hasHandle)
                 {/*do stuff*/};
        }
        catch (AbandonedMutexException)
        {
             hasHandle = true;
             // do stuff
        }
        base.OnStartup(e);
    }

    private void releaseMutex()
    {
        if (mutex!=null)
        {
             if (hasHandle) mutex.ReleaseMutex();
             mutex.Dispose();
        }
    }
}

Is it save to call releaseMutex() ...

  • in the OnExit() method?
    protected override void OnExit(){releaseMutex();}
  • in the ProcessExit event handler?
    AppDomain.CurrentDomain.ProcessExit += (sender,e)=> releaseMutex();
  • in a finalizer?
    ~App(){releaseMutex();}
  • in the unhandled exception event handler?
    AppDomain.CurrentDomain.UnhandledException += (sender,e)=> releaseMutex();

It seems like the OnExit method has the best chance to be in the same thread, but even that seems a sketchy assumption. Is there a way to ignore the same-thread requirement? Or should I create and store a separate thread in conjunction with my mutex?

Community
  • 1
  • 1
HugoRune
  • 13,157
  • 7
  • 69
  • 144
  • The usual way of allowing only a single instance of a program (or a set of programs) is to use the existence - not the state - of a synchronization object (typically an event) to indicate that an instance is already running. But that assumes that you're going to exit if another instance is running; you can't use that approach if you want to wait for the instance to exit and then carry on. It isn't clear to me from your question which situation applies. – Harry Johnston Sep 12 '15 at 10:53

2 Answers2

3

I personally wouldn't bother releasing it at all, especially since you handle AbandonedMutexException.

If a mutex is not used to synchronize threads of the same process there is no need to explicitly release it. When a process terminates OS automatically closes all handles created by the process, such as files, sockets, mutexes, semaphores and event handles .

If you still prefer to release it consider using Application.OnExit() since it is called from the main thread, just like the Startup().

alexm
  • 6,854
  • 20
  • 24
  • The problem with this is that if the thread that originally claimed the mutex exits before the process does, the synchronization fails. – Harry Johnston Sep 12 '15 at 10:46
  • @Harry Johnston perhaps you right. It depends on how mutex is used ("do stuff" part in OP code ) – alexm Sep 12 '15 at 16:24
1

According to my research, every GUI WPF application has a UI thread which can be accessed via Application.Current.Dispatcher (see for example this answer). This UI thread should always remain active for the lifetime of the application.

You can use Dispatcher.CheckAccess to see whether you are running in the UI thread, and if you are not you can use Dispatcher.Invoke to execute an action in the context of the UI thread.

The description of Application.Run implies that Application.OnStartup is always run on the UI thread, but it should not be harmful to check and, if necessary, use the UI thread dispatcher to invoke the action that creates the mutex.

It seems a reasonable guess that Application.OnExit is also always run on the UI thread, but since this does not appear to be documented, you should check and, if necessary, use the UI thread dispatcher to invoke the action that releases the mutex.

As Alexm correctly points out, you do not in fact need to explicitly release the mutex provided that the application is running in its own process (which will usually be the case) but you do need to ensure that the thread the mutex is created on will remain active until you are ready to free it. I believe using the UI thread is the simplest way to ensure this.

Community
  • 1
  • 1
Harry Johnston
  • 35,639
  • 6
  • 68
  • 158