Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is a good pattern for using a Global Mutex in C#?

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

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

One that will work

  • Regardless of the locale my machine is in
  • Is guaranteed to release the mutex properly
  • Optionally does not hang forever if the mutex is not acquired
  • Deals with cases where other processes abandon the mutex
like image 569
Sam Saffron Avatar asked Oct 23 '08 12:10

Sam Saffron


People also ask

What is global mutex?

The global mutex is a recursive mutex with a name of "QP0W_GLOBAL_MTX". The global mutex is not currently used by the pthreads run-time to serialize access to any system resources, and is provided for application use only. The maximum number of recursive locks by the owning thread is 32,767.

How mutex works C#?

A mutual exclusion (“Mutex”) is a mechanism that acts as a flag to prevent two threads from performing one or more actions simultaneously. A Mutex is like a C# lock, but it can work across multiple processes. In other words, Mutex can be computer-wide as well as application-wide.

What is mutex Class?

The Mutex class in C# is a synchronization primitive that can also be used for interprocess synchronization. Let us see how to create a new Mutex. private static Mutex m = new Mutex(); Let us now see how to initialize a new instance of the Mutex class with a Boolean value. private static Mutex m = new Mutex(true);


2 Answers

I want to make sure this is out there, because it's so hard to get right:

using System.Runtime.InteropServices;   //GuidAttribute using System.Reflection;                //Assembly using System.Threading;                 //Mutex using System.Security.AccessControl;    //MutexAccessRule using System.Security.Principal;        //SecurityIdentifier  static void Main(string[] args) {     // get application GUID as defined in AssemblyInfo.cs     string appGuid =         ((GuidAttribute)Assembly.GetExecutingAssembly().             GetCustomAttributes(typeof(GuidAttribute), false).                 GetValue(0)).Value.ToString();      // unique id for global mutex - Global prefix means it is global to the machine     string mutexId = string.Format( "Global\\{{{0}}}", appGuid );      // Need a place to store a return value in Mutex() constructor call     bool createdNew;      // edited by Jeremy Wiebe to add example of setting up security for multi-user usage     // edited by 'Marc' to work also on localized systems (don't use just "Everyone")      var allowEveryoneRule =         new MutexAccessRule( new SecurityIdentifier( WellKnownSidType.WorldSid                                                    , null)                            , MutexRights.FullControl                            , AccessControlType.Allow                            );     var securitySettings = new MutexSecurity();     securitySettings.AddAccessRule(allowEveryoneRule);     // edited by MasonGZhwiti to prevent race condition on security settings via VanNguyen     using (var mutex = new Mutex(false, mutexId, out createdNew, 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)                     throw new TimeoutException("Timeout waiting for exclusive access");             }             catch (AbandonedMutexException)             {                 // Log the fact that the mutex was abandoned in another process,                 // it will still get acquired                 hasHandle = true;             }              // Perform your work here.         }         finally         {             // edited by acidzombie24, added if statement             if(hasHandle)                 mutex.ReleaseMutex();         }     } } 
like image 82
18 revs, 14 users 31% Avatar answered Sep 21 '22 09:09

18 revs, 14 users 31%


Using the accepted answer I create a helper class so you could use it in a similar way you would use the Lock statement. Just thought I'd share.

Use:

using (new SingleGlobalInstance(1000)) //1000ms timeout on global lock {     //Only 1 of these runs at a time     RunSomeStuff(); } 

And the helper class:

class SingleGlobalInstance : IDisposable {     //edit by user "jitbit" - renamed private fields to "_"     public bool _hasHandle = false;     Mutex _mutex;      private void InitMutex()     {         string appGuid = ((GuidAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(GuidAttribute), false).GetValue(0)).Value;         string mutexId = string.Format("Global\\{{{0}}}", appGuid);         _mutex = new Mutex(false, mutexId);          var allowEveryoneRule = new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), MutexRights.FullControl, AccessControlType.Allow);         var securitySettings = new MutexSecurity();         securitySettings.AddAccessRule(allowEveryoneRule);         _mutex.SetAccessControl(securitySettings);     }      public SingleGlobalInstance(int timeOut)     {         InitMutex();         try         {             if(timeOut < 0)                 _hasHandle = _mutex.WaitOne(Timeout.Infinite, false);             else                 _hasHandle = _mutex.WaitOne(timeOut, false);              if (_hasHandle == false)                 throw new TimeoutException("Timeout waiting for exclusive access on SingleInstance");         }         catch (AbandonedMutexException)         {             _hasHandle = true;         }     }       public void Dispose()     {         if (_mutex != null)         {             if (_hasHandle)                 _mutex.ReleaseMutex();             _mutex.Close();         }     } } 
like image 45
deepee1 Avatar answered Sep 22 '22 09:09

deepee1