Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
726 views
in Technique[技术] by (71.8m points)

multithreading - How can I create a System Mutex in C#

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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 Releases do you do? If some other process owned the mutex when you got it, then only your explicit call to WaitOne needs to be Released. If your call to the constructor caused you to own the mutex, and you called WaitOne explicitly, you'll need two Releases.

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...