Only one application instance

Sometimes we need to disallow starting multiple instances of our application (for example, it make sense for music players, applications for Windows Tray, etc.). The easiest and, probably, the most proper way is to use Mutex - a synchronization primitive.

To simplify Mutex using for checking application instances, I've written a tiny helper class:

public class UniqueInstanceChecker
{
    private readonly Mutex _mutex;
    private readonly bool _owner;
 
    public UniqueInstanceChecker(string uniqueId)
    {
        _mutex = new Mutex(true, uniqueId, out _owner);
    }
 
    public bool IsAlreadyRunning()
    {
        return !_mutex.WaitOne(TimeSpan.Zero, true);
    }
 
    public void Release()
    {
        if (_owner)
        {
            _mutex.ReleaseMutex();
        }
    }
}

How to use it? Just create an instance of this class in the application main class (for example, in the Program, MainForm, etc.) - where startup object is located. Pass an identifier of your application to constructor's parameter uniqueId. It's a system-wide Mutex Id that we will check in different application instances. It can be any string, but it should be unique for our application. A good practice is to use a GUID.

Then, on the application start we need to call method IsAlreadyRunning(). It returns true if some application instance is already running. In this case we simply close the current one. And the last, just before the application close, we should call method Release().

How does it work? When the first application instance starts, it creates a Mutex object and becomes its owner. The Mutex is in signaled state. Then we call IsAlreadyRunning(), and WaitOne() inside method makes a request for Mutex. Mutex was just created so the request completes successfully and switches Mutex to non-signaled state.

When we start another application, we create Mutex again. Since it already exists in the system, application instance can't become Mutex owner and uses already existing one. Method WaitOne() fails this time because Mutex is already in a non-signaled state.

When we call Release() in the application that owns Mutex, it releases Mutex and switches it to the signaled state back. All other application instances skip Mutex releasing inside Release() method.