How can I create a system/multiprocess Mutex to co-ordinate multiple processes using the same unmanaged resource.
Background: I've written a procedure that uses a File printer, which can only be used by one process at a time. If I wanted to use it on multiple programs running on the computer, I'd need a way to synchronize this across the system.
A Mutex is a lock that we set before using a shared resource and release after using it. When the lock is set, no other thread can access the locked region of code.
Example 4-1 Mutex Lock ExampleThe get_count() function uses the mutex lock to guarantee that the 64-bit quantity count is read atomically. On a 32-bit architecture, a long long is really two 32-bit quantities. Reading an integer value is an atomic operation because integer is the common word size on most machines.
In C++, we create a mutex by constructing an instance of std::mutex, lock it with a call to the member function lock(), and unlock it with a call to the member function unlock().
You can use the System.Threading.Mutex class, which has an OpenExisting method to open a named system mutex.
That doesn't answer the question:
How can I create a system/multiprocess Mutex
To create a system-wide mutex, call the System.Threading.Mutex constructor that takes a string as an argument. This is also known as a 'named' mutex. To see if it exists, I can't seem to find a more graceful method than try catch:
System.Threading.Mutex _mutey = null;
try
{
_mutey = System.Threading.Mutex.OpenExisting("mutex_name");
//we got Mutey and can try to obtain a lock by waitone
_mutey.WaitOne();
}
catch
{
//the specified mutex doesn't exist, we should create it
_mutey = new System.Threading.Mutex("mutex_name"); //these names need to match.
}
Now, to be a good programmer, you need to, when you end the program, release this mutex
_mutey.ReleaseMutex();
or, you can leave it in which case it will be called 'abandoned' when your thread exits, and will allow another process to create it.
[EDIT]
As a side note to the last sentence describing the mutex that is abandoned, when another thread acquires the mutex, the exception System.Threading.AbandonedMutexException
will be thrown telling him it was found in the abandoned state.
[EDIT TWO]
I'm not sure why I answered the question that way years ago; there is (and was) a constructor overload that is much better at checking for an existing mutex. In fact, the code I gave seems to have a race condition! (And shame on you all for not correcting me! :-P )
Here's the race condition: Imagine two processes, they both try to open the existing mutex at the same time, and both get to the catch section of code. Then, one of the processes creates the mutex and lives happily ever after. The other process, however, tries to create the mutex, but this time it's already created! This checking/creating of a mutex needs to be atomic.
http://msdn.microsoft.com/en-us/library/bwe34f1k(v=vs.90).aspx
So...
var requestInitialOwnership = false;
bool mutexWasCreated;
Mutex m = new Mutex(requestInitialOwnership,
"MyMutex", out mutexWasCreated);
I think the trick here is that it appears that you have an option that you don't actually have (looks like a design flaw to me). You sometimes can't tell if you own the mutex if you send true
for requestInitialOwnership
. If you pass true
and it appears that your call created the mutex, then obviously you own it (confirmed by documentation). If you pass true
and your call did not create the mutex, all you know is that the mutex was already created, you don't know if some other process or thread which perhaps created the mutex currently owns the mutex. So, you have to WaitOne
to make sure you have it. But then, how many Release
s do you do? If some other process owned the mutex when you got it, then only your explicit call to WaitOne
needs to be Release
d. If your call to the constructor caused you to own the mutex, and you called WaitOne
explicitly, you'll need two Release
s.
I'll put these words into code:
var requestInitialOwnership = true; /*This appears to be a mistake.*/
bool mutexWasCreated;
Mutex m = new Mutex(requestInitialOwnership,
"MyMutex", out mutexWasCreated);
if ( !mutexWasCreated )
{
bool calledWaitOne = false;
if ( ! iOwnMutex(m) ) /*I don't know of a method like this*/
{
calledWaitOne = true;
m.WaitOne();
}
doWorkWhileHoldingMutex();
m.Release();
if ( calledWaitOne )
{
m.Release();
}
}
Since I don't see a way to test whether you currently own the mutex, I will strongly recommend that you pass false
to the constructor so that you know that you don't own the mutex, and you know how many times to call Release
.
You can use the System.Threading.Mutex
class, which has an OpenExisting
method to open a named system mutex.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With