Thursday, February 19, 2009

Mutex - A manager class to support both local and global scope

I think Mutex is one such object that I've seen few of us having difficulty or second opinions in usage. After all it does what it's supposed to do and as always I recommend everybody to read documentation to get a good understanding.

There are quite few interesting blogs that go on this topic and here I would like to show a manager class I use (even on terminal services) in my code. Notice that I'm prefixing Global in cases where I want it to be visible for all terminal server sessions; otherwise it's per user session (common usage). Take a look:


using System;
using System.Threading;

namespace myNameSpace
{
/// <summary>
/// MutexManager to support safe Mutex implementation
/// Be sure to check for IsMutexCreated
/// </summary>
public class MutexManager : IDisposable
{
#region Private Properties
private bool disposed = false;
private Mutex _Mutex;
#endregion Private Properties

#region Public Properties
public bool IsMutexCreated { get; private set; }
public bool HasException
{
get { return (ExceptionText != null && ExceptionText.Length > 0); }
}
public string ExceptionText { get; private set; }
#endregion Public Properties

/// <summary>
/// Instantiates the MutexManager with the WaitOne.
/// Check for IsMutexCreated to make sure whether to continue
/// </summary>
/// <param name="handleName">Unique name for each handler</param>
/// <param name="isGlobal">Set to true when using this for Terminal Services</param>
/// <param name="synchronizeRequest">Set to true when the request needs to be synchronized.</param>
public MutexManager(string handleName, bool isGlobal, bool synchronizeRequest)
{
try
{
IsMutexCreated = true;
bool isNewMutexCreated = false;
// Look for global
if (isGlobal)
handleName = @"Global\" + handleName;
//
_Mutex = new Mutex(false, handleName, out isNewMutexCreated);
//
IsMutexCreated = (isNewMutexCreated || synchronizeRequest);
if (IsMutexCreated)
isNewMutexCreated = _Mutex.WaitOne();
}
catch (UnauthorizedAccessException accessException)
{
IsMutexCreated = false;
ExceptionText = accessException.Message;
}
catch (AbandonedMutexException abandonedMutex)
{
IsMutexCreated = false;
ExceptionText = abandonedMutex.Message;
}
}

#region IDisposable Members
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if (!this.disposed)
{
try { _Mutex.ReleaseMutex(); }
catch { }
disposed = true;
}
}
~MutexManager()
{
Dispose(false);
}
#endregion IDisposable Members
}
}

When to consume, I then use it like:


using (MutexManager mutexManager =
new MutexManager("my unique handler name", true, false))
{
// Mutex has exception?
if (mutexManager.HasException)
log(mutexManager.ExceptionText);

// Not synchronizing the Mutex ==> check for whether to continue
if (!mutexManager.IsMutexCreated)
return;

// do work
}

Love coding!

No comments: