Search code examples
c#mutexdeadlockabandonedmutexexception

C# Mutex handling


I am not sure to have well understood how to handle mutex. I need that a process run only once, but if for any reason it crash or close unexpectedly, i also need to reset the abandoned mutex.

For that reason i made an helper calls that try to acquire a mutex (identified by name) with a timeout. If it fail to acquire the mutex then return NULL otherwise it return the mutex that will be handled by the method caller. If the mutex is abandoned i will reset it and consider the request as failed (is not an issue that code is inteded to be used in periodic procedure, if a lock sometimes fail then the procedure will resume into the next run).

What i am asking for is if there is some situation i have not considered that may cause me problem

Here the code :

public class MutexManager
{
    /// <summary>
    /// Try to acquire a global mutex
    /// </summary>
    /// <param name="mutexName">Mutex unique name</param>
    /// <param name="timeout_ms">Timeout in milliseconds (Optional : default = 5000, if <= 0 no timeout is applied, infinite wait and possibile daeadlock) </param>
    /// <returns>The acquired Mutex or null if Mutex can not be acquired</returns>
    public static Mutex TryRegister(string mutexName, int timeout_ms = 5000)
    {
        // unique id for global mutex - Global prefix means it is global to the machine
        string mutexId = string.Format("Global\\{{{0}}}", mutexName);

        bool createdNew;
        var allowEveryoneRule =new MutexAccessRule(    new SecurityIdentifier(WellKnownSidType.WorldSid
                                                       , null)
                                                       , MutexRights.FullControl
                                                       , AccessControlType.Allow
                                                       );
        Mutex mutex = null;
        {
            mutex = new Mutex(false, mutexId, out createdNew);
            var hasHandle = false;

            try
            {
                hasHandle = mutex.WaitOne(timeout_ms, false);
                if (hasHandle == false)
                    return null;
                else
                    return mutex;
            }
            catch (AbandonedMutexException)
            {
                mutex.ReleaseMutex();
                mutex.Close();
                mutex.Dispose();
                return null;
            }
            catch (Exception err)
            {
                return null;
            }
        }
    }
}

Here how i will use the class above. The code below is used in periodic procedure (scheduled throght windows scheduler) so if sometimes thing gone wrong is not an issue (next run will do the work) the important think is that there are no race-condition or deead-lock

using ( var mutex = MutexManager.TryRegister("procedureName") )
{
    ...DO WORK
}

Solution

  • A Mutex is "owned" by a single process, and in the event the process crashes or closes the Mutex will be released.

    If the process crashes and the Mutex is freed then it is considered "Abandoned", which is a way to signal that the original process no longer owns it -- but also didn't expliticly release it.

    What I'm not quite understanding in your question or code is the handling of an abandoned Mutex. The helper will only return a Mutex if it was not previously abandoned. In the event it was abandoned the code successfully retrieves the Mutex, then releases it and returns without providing a Mutex at all.

    That might be the intention, but it's somewhat hard to understand based on the wording of the question. If the helper is intended to reset and return the Mutex then the handling of the AbandonedMutexException doesn't look correct, as it will always return null.