Multithreading: “sharing” mutexes

In the previous post, we’ve looked at some important features provided by the Mutex kernel object. Today we’re going to keep looking at mutexes and we’ll take a look at how we can create named mutexes and use them for synchronizing access to shared state.

true that using kernel objects has costs: when you wait, you’ll always incur in a context switch, which really translates into several “wasted” CPU instructions. But it’s also true that it facilitates other scenarios that the other high level primitives can’t handle. As we’ve seen in the previous post, the Mutex class offers several constructors. Several of them allow you to pass a name and return a reference to a new (or existing) named mutex. It’s

Whenever you create a named kernel object, you can recover that object by its name. This means that you can use it for (and this is just an example) interprocess synchronization. It’s also important to keep in mind that you should probably secure a named kernel object so that you can limit the people that can access and use it.

To illustrate some of its potential, we’re going to write  a simple console app that lets you run only one instance at a time. When using a mutex for this we have several approaches. Here are some of them:

  • we can wait on  a mutex and return imediately by passing 0 to one of the WaitOne method overloads that receive a timeout;
  • we can try to call the static OpenExisting method to see if there already exists with the predefined name. The method throws a WaiHandleCannotBeOpenedException when it can’t find a kernel object with that name;
  • we can skip waiting entirely if we use the constructor that has an out created parameter.

Ok, lets see how we can implement these options. I’m going to start from option1. Here’s some code that tries to use that approach:

var mutex = new Mutex(false, "test");
try {
   if( !mutex.WaitOne(0, false) ) {
      Console.WriteLine("Can only run one application instance");
      return;
    }
  }
  catch (AbandonedMutexException) {
    //ok, there”s probably some clean up here
    //because even if you kill the process on task manager, 
    //you won”t get this when you run the app again
    //check this post http://ayende.com/Blog/archive/2008/02/28/The-mysterious-life-of-mutexes.aspx
    Console.WriteLine("Previous app wasn”t closed correctly");
    mutex.Close();
    return;
  }
  try{
     while (Console.ReadKey().Key != ConsoleKey.X) {
        Console.WriteLine();
     }
  }
  finally{
     mutex.ReleaseMutex();
  }
  mutex.Close();

If you recall it,calling one of the WaitXXX methods might throw an exception because we might have an abandoned mutex. Interestingly,you won’t be getting this exception with the console sample (even if you kill the managed process by using task manager and skip the cleanup). The docs don’t mention anything about this behavior, but it does really look like the CLR is cleaning up for you (if you try abandoning a mutex on a thread and then reacquiring it on another on the same app then yes, you’ll get the exception!). Btw, I’ve found an post by Ayende where a comment refers this behavior. Despite that, I decided to wrap the WaitOne call because I think that doing this is a recommended practice (after all, we can’t know if this behavior will change in the future).

Going back to our list, we can see that option 2 relies on the OpenExisting static method. In this case, we don’t even need to acquire the mutex by waiting on it:

Boolean exists = false;
Mutex mutex = null;
try {
      mutex = Mutex.OpenExisting("test");
      exists = true;
}
catch (WaitHandleCannotBeOpenedException) {
     mutex = new Mutex(false, "test");
}
if(exists) {
      Console.WriteLine("Can only run one application instance");
      return;
}
while (Console.ReadKey().Key != ConsoleKey.X) {
   Console.WriteLine();
}
mutex.Close();

Option 3 is just a variation of this approach:

Boolean created;
var mutex = new Mutex(false, "test", out created);
if( !created ){
    Console.WriteLine("Can only run one application instance");
    return;
}
while( Console.ReadKey().Key != ConsoleKey.X){
    Console.WriteLine();
}
mutex.Close();

ok, I guess that it’s all for today. I’m sure there are lots of things you can do with this kernel object, but I guess that these and yesterday’s post should give you several hints on how to use it.

Keep tuned for more on multithreading…

Advertisements

~ by Luis Abreu on May 15, 2009.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: