SynchronizationHelpers.cs

using System.Reflection;
using System.Security.AccessControl;
using System.Security.Principal;
using System.Runtime.InteropServices;
 
namespace GenXdev.Helpers
{
    public static class SynchronizationHelpers
    {
        public static void ExecuteMachineWideMutuallyExclusive(string Id, ThreadStart Callback)
        {
            // get application GUID as defined in AssemblyInfo.cs
            Id = !String.IsNullOrWhiteSpace(Id) ? Id :
                ((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
            Id = string.Format("Global\\{{{0}}}", Id);
 
            // Need a place to store a return value in Mutex() constructor call
 
            // 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);
 
            // edited by MasonGZhwiti to prevent race condition on security settings via VanNguyen
            using (var mutex = new Mutex(false, Id, out bool createdNew))
            {
                // edited by acidzombie24
                var hasHandle = false;
                try
                {
                    try
                    {
                        // note, you may want to time out here instead of waiting forever
                        // edited by acidzombie24
                        hasHandle = 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 accquired
                        hasHandle = true;
                    }
 
                    // Perform your work here.
                    Callback();
                }
                finally
                {
                    // edited by acidzombie24, added if statement
                    if (hasHandle)
                        mutex.ReleaseMutex();
                }
            }
        }
    }
}