Sometimes, you may not want a user to launch multiple instances of your program, or you may have a processor or I/O intensive scheduled task that runs every few minutes and you want to make sure that if it is started again before the last instance has finished, it simply exits immediately. One way to check to see if your program is already running is to look at the list of running processes:
namespace RunningInstance
{
using System;
using System.Diagnostics;
using System.Reflection;
class Program
{
static void Main(string[] args)
{
if (RunningInstance())
{
Console.WriteLine(
"Another instance of this process was already running, exiting...");
return;
}
}
static bool RunningInstance()
{
Process current = Process.GetCurrentProcess();
Process[] processes = Process.GetProcessesByName(current.ProcessName);
foreach (Process p in processes)
{
if (p.Id != current.Id)
{
if (Assembly.GetExecutingAssembly().Location.Replace("/", @"\") ==
current.MainModule.FileName)
{
return true;
}
}
}
return false;
}
}
}
However, suppose you have a multi function console application that accepts a dozen different command line arguments to perform different jobs, all of which run as separate scheduled tasks at overlapping intervals. If this is the case, then checking the list of running processes may well find your executable already running, but have no idea which command line argument was used to start it. I tried adding:
Console.WriteLine("Instance started with args: '{0}'", p.StartInfo.Arguments);
above the "return true
" statement in RunningInstance()
but it will not print the command line args used to start it. Let's suppose we add 2 classes to our project. Task1
and Task2
. For the sake of simplicity, they both look something like this:
namespace RunningInstance
{
using System;
using System.Threading;
public class Task1
{
public void Start()
{
Console.WriteLine("Starting Task 1");
}
}
}
Task 2 is exactly the same, except it prints "Starting Task 2
". If we keep our RunningInstance
check in place, Main()
now looks like this:
static void Main(string[] args)
{
if (RunningInstance())
{
Console.WriteLine("An instance of this application is already running. Exiting.");
Console.ReadLine();
return;
}
if(args.Length < 1)
{
Console.WriteLine("Unrecognized Command.");
return;
}
switch (args[0])
{
case "-task1":
var t1 = new Task1();
t1.Start();
break;
case "-task2":
var t2 = new Task2();
t2.Start();
break;
default:
Console.WriteLine("Unrecognized Command.");
break;
}
}
Task 2 will not run, if task 1 is still running, and vice versa. However, suppose the two tasks are completely unrelated. The first is only a minor chore, that simply counts the number of items marked as "queued" in a database table and sends out an email if the number is too high, while task 2 is a much lengthier process that FTPs files. We may need both of these tasks to run as scheduled, but not want multiple instances of either task to run at the same time. How can we achieve this? We use a Mutex. Mutex is an abbreviation of "Mutual exclusion" and is traditionally used in multi threaded applications to avoid the simultaneous use of a common resource, such as a global
variable. After adding a mutex to each task, our final code looks like this:
static void Main(string[] args)
{
if(args.Length < 1)
{
Console.WriteLine("Unrecognized Command.");
return;
}
switch (args[0])
{
case "-task1":
var t1 = new Task1();
t1.Start();
break;
case "-task2":
var t2 = new Task2();
t2.Start();
break;
default:
Console.WriteLine("Unrecognized Command.");
break;
}
}
namespace RunningInstance
{
using System;
using System.Threading;
public class Task1
{
private static Mutex mutex1;
public void Start()
{
bool createdNew;
mutex1 = new Mutex(true, "RunningInstance.Task1", out createdNew);
if (!createdNew)
{
Console.WriteLine("Exiting: Instance already running");
return;
}
Console.WriteLine("Starting Task 1");
}
}
}
namespace RunningInstance
{
using System;
using System.Threading;
public class Task2
{
private static Mutex mutex1;
public void Start()
{
bool createdNew;
mutex1 = new Mutex(true, "RunningInstance.Task2", out createdNew);
if (!createdNew)
{
Console.WriteLine("Exiting: Instance already running");
return;
}
Console.WriteLine("Starting Task 2");
}
}
}
Each Task has its own Mutex, uniquely named. If the mutex already exists, then that code must already be running, so exit, otherwise, run. Couldn't be simpler. By using this particular overload of the constructor, we don't even need to worry about releasing the mutex at the end of the program.