Tuesday, November 15, 2016

How to make .Net process Singleton

Its a common scenario we encounter in traditional windows application development that we need to limit our process's instances to one. Especially if its a giant LOB WPF or WinForms which consumes good amount of memory, we will be forced to limit the instances of application to one. This post is explaining how that can be done.

Please note this is a solved problem. Many of us are doing it.

Using process name  

This is the most common method we can see to limit the process instance. Every time the process will check whether there is any other processes in the machine running with same name. Code snippet below
class ProcessHelper
{
    public void PrintIfThereIsAnotherProcessInstanceRunning()
    {
        IProcessInstanceDetection processDetection = new NameBasedDetection();
 
        bool areThereAnotherInstances = processDetection.IsAnotherInstanceRunning();
 
        Console.WriteLine($"Current process name {Process.GetCurrentProcess().ProcessName}.");
        Console.WriteLine($"Are there another instances : {areThereAnotherInstances}");
        //Handle the result.May be terminate second instance. 
    }
}
interface IProcessInstanceDetection
{
    bool IsAnotherInstanceRunning();
}
class NameBasedDetection : IProcessInstanceDetection
{
    public bool IsAnotherInstanceRunning()
    {
        return Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName)
                      .Count() > 1;
    }
}
class MutexBasedDetection : IProcessInstanceDetection
{
    private const string MutexName = "SomeGUID";
 
    public bool IsAnotherInstanceRunning()
    {
        bool created;
        Mutex mutex = new Mutex(true, MutexName, out created);
        return created == false;
    }
}
The interface is used for easily switching the logic. Here the name of the current process is used to get processes with same name and if there are more than one, current process may terminate. The code to terminate is not present in this sample.

First time when the process runs the count will be 1 and the process can continue. Next time the count will be 2 and its > 1 so the second process needs to be terminated itself. It's not a managed termination. Process has to exit itself. 

Pros

Simple mechanism to implement.

Cons

If someone rename the exe file name, the process name will change and second instance will run. Also if some other application from different vendor is also using the same exe name, our application will not run. Especially if our exe name is generic such a monitor.exe or starter.exe etc...  

Using Mutex

Here we use Mutex which is visible to all processes. The implementation class for the Mutex based duplicate process instance detection is below.
class MutexBasedDetection : IProcessInstanceDetection
{
    private const string MutexName = "SomeGUID";
 
    public bool IsAnotherInstanceRunning()
    {
        bool created;
        Mutex mutex = new Mutex(true, MutexName, out created);
        return created == false;
    }
}
Hope we all know what is Mutex means. If not please refresh. Here when the code is executed for first time, the Mutex will be created and it detect as first instance. Next time when the same process's different instance is started, the Mutex will not get created and the program can terminate itself.

Since the first code snippet is showing the usage, here only the new class is included.

One problem we can see here. If we use "SomeGUID" as Mutex name, there are chances for our logic to fail, if any other process create a Mutex with same name. So better generate a GUID and include that in our source code. Practically the same GUID will not be generated second time.

Pros

  • Even the exe is renamed, it will detect second process instance.

Cons

  • The Mutex name is the key part here. If its .Net, anyone can decompile the app and find the value if they really want to make trouble.
  • If same process try to check whether there are only single instance, the result may vary. So need to tweak the sample code above to handle.Please note its not because of this approach, its because of the logic in sample code.
We can think of many ways to make our process single instance. But these are the common ways.

No comments: