views:

4346

answers:

3

The Mutex class is very misunderstood, and Global mutexes even more so.

What is good, safe pattern to use when creating Global mutexes?

+26  A: 

I really want to make sure this is out there, cause its so hard to get right.

    // unique id for global mutex - Global prefix means it is global to the machine
    const string mutex_id = "Global\\{B1E7934A-F688-417f-8FCB-65C3985E9E27}";

    static void Main(string[] args)
    {
        using (var mutex = new Mutex(false, mutex_id))
        {
            // edited by Jeremy Wiebe to add example of setting up security for multi-user usage
            var allowEveryoneRule = new MutexAccessRule("Everyone", MutexRights.FullControl, AccessControlType.Allow);
            var securitySettings = new MutexSecurity();
            securitySettings.AddAccessRule(allowEveryoneRule);
            mutex.SetAccessControl(securitySettings);

            //edited by acidzombie24
            var hasHandle = false;
            try
            {
                try
                {
                    // note, you may want to time out here instead of waiting forever
                    //edited by acidzombie24
                    //mutex.WaitOne(Timeout.Infinite, false);
                    hasHandle = mutex.WaitOne(5000, false);
                    if (hasHandle == false) return;//another instance exist
                }
                catch (AbandonedMutexException)
                {
                    // Log the fact the mutex was abandoned in another process, it will still get aquired
                }

                // Perform your work here.
            }
            finally
            {
                //edit by acidzombie24, added if statemnet
                if(hasHandle)
                    mutex.ReleaseMutex();
            }
        }
    }
Sam Saffron
This could possibly be improved to include a timeout
Sam Saffron
Add improved by using a single try/catch/finally.
kenny
A single try catch does not work here, you still want to do work if you get an abandoned mutex
Sam Saffron
Please note that implementers should not forget to use guidgen.exe to replace the Guid value in the Mutex name with a new Guid.
0xA3
Please note that this example will wait infinitely until another process releases the Mutex.
Liam
You've also missed a VERY important point, which is that you're creating the mutex with inherited permissions rather than explicitly specifying them. That'll be quite a lot of fun when a different user account tries to access a held mutex...
Greg Beech
@Greg, feel free to step in and correct this, it is a community wiki
Sam Saffron
It'd be nice if an expert could confirm if dtroy's answer is correct or not.
blak3r
I hope you dont mind me changing this code. My app would run my code unless i checked the return value and exit.
acidzombie24
Damn I love this site. This example sorted out a bug I was having first try.
Ubiquitous Che
I wonder how *hasHandle* is set in the case of an *AbandonedMutexException*. Shouldn't it be the case, to make a release possible? Is this variable neccessary at all? A `if( !mutex.WaitOne(5000, false))` returns when the handle is not aquired - in all other cases the mutex is aquired and should be released ...
tanascius
+2  A: 

Would this be the right way of doing the same thing with a timeout ?

// unique id for global mutex - Global prefix means it is global to the machine
const string mutex_id = "Global\\{B1E7934A-F688-417f-8FCB-65C3985E9E27}";

static void Main(string[] args)
{
    using (var mutex = new Mutex(false, mutex_id))
    {
        bool bHadMutex = false;
        try
        {
            try
            {
                // note, you may want to time out here instead of waiting forever
                bHadMutex = mutex.WaitOne(200, false);
            }
            catch (AbandonedMutexException)
            {
                // Log the fact the mutex was abandoned in another process, it will still get aquired
                bHadMutex = true;
            }

            // Perform your work here.
        }
        finally
        {
            // ReleaseMutex will throw  ApplicationException  if the calling thread does not own the mutex, so we have to check
            if (bHadMutex)
                mutex.ReleaseMutex(); // otherwise
        }
    }
}
dtroy
+2  A: 

This example will exit after 5 seconds if another instance is already running.

// unique id for global mutex - Global prefix means it is global to the machine
const string mutex_id = "Global\\{B1E7934A-F688-417f-8FCB-65C3985E9E27}";

static void Main(string[] args)
{

    using (var mutex = new Mutex(false, mutex_id))
    {
        try
        {
            try
            {
                if (!mutex.WaitOne(TimeSpan.FromSeconds(5), false))
                {
                    Console.WriteLine("Another instance of this program is running");
                    Environment.Exit(0);
                }
            }
            catch (AbandonedMutexException)
            {
                // Log the fact the mutex was abandoned in another process, it will still get aquired
            }

            // Perform your work here.
        }
        finally
        {
            mutex.ReleaseMutex();
        }
    }
}
Liam