Yesterday I ran into some weirdness while trying to implement System.Threading.Mutex synchronization between one of my Windows services and a colleague’s application. The synchronization worked great in the debugger, but when running on a test system, the apps stomped all over each other.
Both had code somewhat like this:
System.Threading.Mutex mutex = new System.Threading.Mutex(false, "SHARED_MUTEX"); //some prep work //get the mutex for the shared resource mutex.WaitOne(); //work with the shared resource //done, release the mutex mutex.ReleaseMutex();
I double checked the system mutex name, that was fine. Didn’t seem like it should be a permissions issue. The note in the documentation about Terminal Services kept nagging at me. We weren’t running Terminal Services on the virtual test machine, but we were using Remote Desktop (Terminal Services lite, if you will).
I started by prefacing the mutex from my colleague’s app with “Global\”. All of a sudden, the apps were working fine on the test system. But I hadn’t changed my windows service app’s mutex name to look at “Global\”!
System.Threading.Mutex mutex = new System.Threading.Mutex(false, "Global\\SHARED_MUTEX"); //some prep work //get the mutex for the shared resource mutex.WaitOne(); //work with the shared resource //done, release the mutex mutex.ReleaseMutex();
It turns out that because my portion was a windows service, it’s execution context changed from being part of the Terminal Services/Remote Desktop session, to being global. The other app was still in the Terminal Services/Remote Desktop session context because it was an interactive application. In order for it to lock on the same mutex, it had to explicitly look for the mutex in the Global namespace rather than the Local session namespace.
Makes sense, I guess, but still a little weird. Glad I didn’t spend all day tracking it down either…