Cross Process Threading, Synchronization, EventWaitHandles and Mutexes

12 April 2012

As a programmer who normally does websites and non-complicated things, I've been working on a cool / crazy / complex solution which involves multiple processes and a lot of moving parts. So I thought I'd share some of the gotchas that I came across while trying to do two things:

1) Cross Process Thread Signaling

If you need a thread to pause until another thread (on another process) has completed some work, you can use a named EventWaitHandle. Gotchas are:

  • This is probably documented somewhere in tiny font / I have bad reading skills, but it isn't enough to name your waithandles to have them work cross-process; you need to make sure they start with the "Global\" prefix in the name you give them
  • You may get an UnauthorizedAccessException when trying to create a WaitHandle once it already exists in another process/thread - in this instance, you can catch it and use the EventWaitHandle.OpenExisting method to get the appropriate waithandle

Here's an example:

    private static EventWaitHandle _handle;
    public static EventWaitHandle handle
    {
        get
        {
            if (_handle == null)
            {
                var users = new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null);
                var rule = new EventWaitHandleAccessRule(users, EventWaitHandleRights.Synchronize | EventWaitHandleRights.Modify, AccessControlType.Allow);
                var security = new EventWaitHandleSecurity();
                security.AddAccessRule(rule);

                bool created;
                try
                {
                    _handle = new EventWaitHandle(false, EventResetMode.AutoReset, @"Global\MyWaitHandle", out created, security);         
                }
                catch (UnauthorizedAccessException uae)
                {
                    //http://stackoverflow.com/questions/1784392/my-eventwaithandle-says-access-to-the-path-is-denied-but-its-not
                    _handle = EventWaitHandle.OpenExisting(@"Global\MyWaitHandle", EventWaitHandleRights.Synchronize | EventWaitHandleRights.Modify);
                }

            }
            return _handle;
        }
    }

    //and to use the handle, call handle.Set() to allow threads to continue, and handle.WaitOne() to ask them to pause until the next set...

2) Cross Process Resource Locking

If you've got a shared resource across processes, lock statements and the ReaderWriterLockSlim class don't work, so you really only have two options: Mutexes, or Semaphores (which are like a super Mutex).

The basic setup of a Mutex can be seen from this StackOverflow post, but the main gotchas that I encountered were:

  • The same catch about requiring the 'Global\' prefix in your Mutex name exists, ie: new Mutex(false, @"Global\MyMutex", out newMutex)
  • When creating the mutex object, .WaitOne on the secondary process seems to always lock (regardless of .ReleaseMutex calls) unless you create the Mutex specifying initiallyOwned as false

Here's an example with a static instance of a mutex, and surrounding critical / lock sections of code:

    private static Mutex _mutexLock;
    private static Mutex MutexLock
    {
        get
        {
            if (_mutexLock == null)
            {
                bool newMutex;
                _mutexLock = new Mutex(false, @"Global\MyMutex", out newMutex);

                var allowEveryoneRule = new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), MutexRights.FullControl, AccessControlType.Allow);
                var securitySettings = new MutexSecurity();
                securitySettings.AddAccessRule(allowEveryoneRule);
                _mutexLock.SetAccessControl(securitySettings);
            }
            return _mutexLock;
        }
    }

    public static void ImportantMethod()
    {           
        //using .WaitOne and .ReleaseMutex to simulate lock() { } sections
        try
        {
            MutexLock.WaitOne(new TimeSpan(0,2,0));
            // do some important stuff in here
            Thread.Sleep(3000);
        }
        finally
        {
            MutexLock.ReleaseMutex();
        }
    }

Anyway, my brain hurts and it's my work's office birthday party so I am super glad it's the weekend!

Tags: AutoResetEvent, cross process, EventWaitHandle, locking, mutex, synchronization, threading

Add a Comment

No Comments