gerrod
gerrod

Reputation: 6627

Does a Mutex ever close by itself?

I'm trying to work out when is the right time to use ReleaseMutex, and when is the right time to use Close.

We are (effectively) writing an "auto-updater" type application in C#. The user can run more than one instance of the auto-updater at the same time, however each one must wait for other instances to finish before it proceeds. So effectively, the application flow is as follows:

It's that final step that I'm wondering about. If a particular application instance created the Mutex, then I figured it would be safe for that instance to also close the Mutex; but, I'm not sure what this would do to other application instances that are then waiting on that Mutex.

A safer option seems to be to let each application simply release the mutex; however, I don't know in this case if the mutex would ever be destroyed?

private const string _mutexName = "NinjaMutexAwesomePants";
private static int _threadId;

void Main()
{
    Task.Factory.StartNew(AcquireMutex);
    Task.Factory.StartNew(AcquireMutex);
    Task.Factory.StartNew(AcquireMutex);
}

void Trace(int threadId, string text, params object[] args) 
{
    var trace = String.Concat(
        String.Format("{0:hh:mm:ss.ffff} T{1}: ", DateTime.Now, threadId),
        String.Format(text, args));

    Console.WriteLine(trace);
}

void AcquireMutex()
{
    var threadId = Interlocked.Increment(ref _threadId);

    Trace(threadId, "Started!");

    bool createdNew;
    var mutex = new Mutex(false, _mutexName, out createdNew);

    if (createdNew)
        Trace(threadId, "I am the creator!");
    else
        Trace(threadId, "I did not create the mutex.");

    try
    {
        var isOwner = mutex.WaitOne(TimeSpan.FromSeconds(5));

        if (isOwner)
            Trace(threadId, "I am the owner of the mutex!");
        else
            Trace(threadId, "I couldn't acquire the mutex.");

        if (isOwner) 
        {
            Thread.Sleep(TimeSpan.FromSeconds(1));

            if (createdNew)
                mutex.Close();
            else
                mutex.ReleaseMutex();

            Trace(threadId, "I have released the mutex.");
        }
    }
    catch (Exception ex)
    {
        Trace(threadId, "{0}: {1}", ex.GetType().Name, ex.Message);
    }
}

However, this didn't really clear things up for me. Seemingly, always using ReleaseMutex is the safest option (instead of calling Close), however this also seems like the mutex is never closed even after all threads have released the mutex. In fact, in the code above - if the creator thread also closes the mutex, the consumer threads can never acquire it.

So, my questions are twofold:

  1. What's the best policy for acquiring/releasing a mutex in this scenario?
  2. If I only ever use ReleaseMutex, does the mutex close itself after all threads have released it?

Upvotes: 0

Views: 550

Answers (1)

Denis Itskovich
Denis Itskovich

Reputation: 4523

I would suggest to implement IDisposable for this purpose

class Updater : IDisposable
{
    private readonly Mutex _mutex;

    public Updater(string mutexName)
    {
        bool createdNew;
        _mutex = new Mutex(false, mutexName, out createdNew);
        if (!_mutex.WaitOne(TimeSpan.FromSeconds(5)) throw new Exception("I could not acquire mutex");

    }

    public void Update()
    {
        // Perform the update
    }

    public void Dispose()
    {
        _mutex.ReleaseMutex();
        _mutex.Close();
    }
}


using (var updater = new Updater("NinjaMutexAwesomePants"))
{
    updater.Update();
}

Upvotes: 1

Related Questions