In the past, whenever I constrained an application to having only a single instance running at any given time, I naively walked a list of running processes to find a process with the same name as the currently-running process. If it exists, there’s another instance, if not I would assume there is no other instance. This was a quick and dirty approach, because I didn’t know of any other way. Of course, this would fail if the user renamed the process; total fail.
In CLR via C# by Jeffrey Richter, a much quicker solution is presented (leaving my naive solution to be only dirty). This solution uses a Semaphore to count references to a resource (the application) as it will be managed by the operating system.
Here is a simple console application to display how this would work:
class Program
{
const string Id = "af49d266-e4f4-4a63-b73c-f62c1144b584";
static void Main(string[] args)
{
bool thisInstance;
using (var semaphore = new Semaphore(0, 1, Id, out thisInstance))
{
if (thisInstance)
{
Console.WriteLine("This is the first instance!");
Console.ReadLine();
}
else
{
Console.WriteLine("There is another instance running.");
Console.ReadLine();
}
}
}
}
A semaphore is designed to limit access to a given resource. If you read the Wikipedia – Semaphore article, you’ll see that a semaphore is described as a librarian handing out passes to study rooms. The librarian doesn’t care who is in which room, only whether there are rooms available. There could be 10 rooms, there could be 100. In this single application example, we have 1 available resource which is the application identified by a constant Guid – “af49d266-e4f4-4a63-b73c-f62c1144b584”. Because the operating system will use this string to uniquely identify our application, I’ve chosen a Guid over something simple like “MySemaphore” because the chances of a Guid being duplicated are theoretically nil.
Using this Semaphore constructor:
public Semaphore(
int initialCount,
int maximumCount,
string name,
out bool createdNew
)
we can create a binary semaphore.
A binary semaphore allows us to have an on/off switch for running our application — is the resource available or not? When we have 1 resource available, and the first application starts up, it decrements the count of available resources to 0. If this decrement occurs, the createdNew out parameter will be true. On the other hand, if an application starts up and the semaphore’s available resource count is 0, createdNew will be false.
Notice in the code above that Console.ReadLine() is used in each block of the if statement to block execution. Why is this not located at the end of the Main method?
It’s because Semaphore is a type derived from WaitHandle. WaitHandle implements the IDisposable interface, which is why the Semaphore is wrapped in a using block. When the code exits this using block, semaphore.Dispose() executes semaphore.Close() and the currently-held resource is released. This increments the available resources back to the maximum value of 1. In a real application, the first block would call the Application’s Run() method and the else block would either display a message, terminate silently, or switch to the first process.
It is also possible to have any subsequent processes wait for the semaphore to release its lock on the resource. This would be accomplished by calling semaphore.WaitOne() in the else block:
class Program
{
const string Id = "af49d266-e4f4-4a63-b73c-f62c1144b584";
static void Main(string[] args)
{
bool thisInstance;
using (var semaphore = new Semaphore(0, 1, Id, out thisInstance))
{
if (thisInstance)
{
Console.WriteLine("This is the first instance!");
Console.ReadLine();
// Release resource
semaphore.Release();
}
else
{
Console.WriteLine("There is another instance running.");
// Wait for resource
semaphore.WaitOne();
Console.WriteLine("There is now the only instance.");
Console.ReadLine();
}
}
}
}
Wait a second. Didn’t I say that wrapping the Semaphore object in a using block would call Close()? Why did I have to explicitly call semaphore.Release()?
The answer to this is Garbage Collection. Sure, Close() will be called (and thus, Release() is called and signals all waiting threads that the resource is available) when the using block exits, but this will only happen when the object is disposed. If you plan to queue up applications (or windows, dialogs, or any other resource), note this signaling behavior.
Code
I’ve decided to start making code from my blog posts available from a single github repository.
https://github.com/jimschubert/blogs