LP on .NET

September 9, 2009

Of Mutexes and Neutral Zones

Filed under: .NET,C#,Software Development — Larry Parker @ 7:56 am

A mutex (“mutual exclusion”) is a synchronization device used to ensure exclusive access to a system resource.  In a limited sense, a mutex is similar to (although costlier than) the lock keyword in that it can be used to protect state variables that are under contention by multiple threads.

But the mutex has the ability to be used not only across threads, but across processes (hence the additional cost over a mere lock).

The Canonical Mutex Example

The oft-cited mutex example is that of ensuring that an application be run just once.  Here’s the code to do that:

static void Main(string[] args)
{
    Mutex mutex = new Mutex(false, "My killer app");

    if (mutex.WaitOne(3000))
    {
        Console.WriteLine("This application is already running.");
        return;
    }

    try
    {
        RunTheApp();
    }
    finally
    {
        mutex.ReleaseMutex();
    }
}

In this example, we create a named mutex that becomes associated with an operating-system object of the name “My killer app”.  Since the name is system-wide, it is important to give it a globally unique name.  We also specified false in the constructor to indicate that we don’t need to initially own the mutex.

We then wait to acquire the mutex.  If we get it within 3 seconds, we hold onto it and run the app.  If we don’t get it within 3 seconds we give the user a message that somebody else is running the app, and then exit out.

Notice that after acquiring the mutex we purposely don’t release it until the application is finished.  This prevents anyone else on the current machine from getting access to our named mutex (including another instance of our app).

The mutex is ultimately released when the app terminates.  To guarantee this, it’s best to put it in a try/finally block.

This is a nice use for a mutex, but mutexes have other uses, even within a single running process.

Protecting the Neutral Zone

The Neutral Zone was a fictitious buffer zone in Star Trek that separated the Federation from the likes of the Romulans and Klingons.  If a ship from either side entered the Neutral Zone, it was usually considered an act of war.  But as long as both sides did not enter at the same time, things could typically be ironed out between both parties to avoid catastrophe.

Assume that we’re writing a Star Trek simulation game in C#.  Let’s protect our Neutral Zone with a mutex.

We will name our mutex “The Neutral Zone”.  As long as the code instantiates a mutex with this name and waits on it, we will properly protect the Neutral Zone and avoid interstellar war.

Our main code might look something like this:

public static void Main()
{
    FederationStarship enterprise = new FederationStarship();
    RomulanWarbird warbird = new RomulanWarbird();

    Thread thread1 = new Thread(enterprise.Explore);
    Thread thread2 = new Thread(warbird.Conquer);

    thread1.Start();
    thread2.Start();

    thread1.Join();
    thread2.Join();

    Console.WriteLine("Press a key to exit...");
    Console.ReadLine();
}

We start by creating an instance of the FederationStarship class, as well as an instance of the RomulanWarbird class.  Next we spin up a thread for each, provide an entry point, start our threads, and wait for our ships to finish their business of exploration or conquering.

The two classes look like this:

public class FederationStarship
{
    public void Explore()
    {
        for (int i = 0; i < 2; i++)
            EnterNeutralZone();
    }

    public void EnterNeutralZone()
    {
        Mutex _mutex = new Mutex(false, "The Neutral Zone");

        Console.WriteLine("{0,2} Enterprise waiting to enter the Neutral Zone", DateTime.Now.ToString("h:mm:ss.fff"));
        _mutex.WaitOne();

        Console.WriteLine("{0,2} Enterprise entering the Neutral Zone", DateTime.Now.ToString("h:mm:ss.fff"));

        // Simulate exploring the Neutral Zone
        Thread.Sleep(300);

        Console.WriteLine("{0,2} Enterprise exiting the Neutral Zone", DateTime.Now.ToString("h:mm:ss.fff"));
        _mutex.ReleaseMutex();
    }
}

public class RomulanWarbird
{
    public void Conquer()
    {
        for (int i = 0; i < 2; i++)
            EnterNeutralZone();
    }

    public void EnterNeutralZone()
    {
        Mutex _mutex = new Mutex(false, "The Neutral Zone");

        Console.WriteLine("{0,2} Warbird waiting to enter the Neutral Zone", DateTime.Now.ToString("h:mm:ss.fff"));
        _mutex.WaitOne();

        Console.WriteLine("{0,2} Warbird entering the Neutral Zone", DateTime.Now.ToString("h:mm:ss.fff"));

        // Simulate some mischief in the Neutral Zone
        Thread.Sleep(500);

        Console.WriteLine("{0,2} Warbird exiting the Neutral Zone", DateTime.Now.ToString("h:mm:ss.fff"));
        _mutex.ReleaseMutex();
    }
}

Running the program produces the following output:

image

Notice that we have successfully prevented both ships from entering the Neutral Zone at the same time.  If a ship tries to enter and another ship is already inside, it will wait until it leaves.  This is because of the mutex and our consistent usage of it in both the FederationStarship and RomulanWarbird classes.

If one of the ships decided not to use it, then they could have entered the Neutral Zone without regard to the other ship’s presence.  The Romulans might be able to pull this off with their cloaking device, but for the sake of argument let’s just say that today they are following protocol and decide to use our mutex.

Design Thoughts

As I mentioned earlier, synchronizing with a mutex is a bit costlier than synchronizing with a lock (on the order of milliseconds as opposed to nanoseconds).  So why use it within a single application?

We certainly wouldn’t use a mutex to simply protect an instance field from multiple threads.  A lock would do fine and would be very fast.

I suppose we could have created a static class that encapsulated a public synchronization object, and both ship classes could have locked around that.  Or we could have shared a local mutex (i.e. non-named) between the classes in some fashion and not have resorted to the heavier named mutex (which associates the mutex with an operating system object of that name).

These are definitely some avenues to consider.  The advantage of the named mutex is that it is easily referenced by classes that know nothing about each other.  You simply instantiate a new mutex of that same name, and don’t have to worry about sharing an existing mutex instance between decoupled classes.

And if you need to protect a resource across processes, the named mutex is the way to go.

Hope this was useful reading, and help keep the Neutral Zone safe!  🙂

Advertisements

September 3, 2009

Almost 1000 Hits!

Filed under: .NET,blogging,C#,Software Development — Larry Parker @ 11:49 pm

I was going to wait until I got 1000 hits on my blog, but then I thought it might be more nostalgic to take a screenshot while it was still in triple digits.  So here it is:

Almost1000

Next stop 1000, and thanks for reading!!  🙂

Blog at WordPress.com.