如何在C#中创建系统互斥锁?

C. *_*oss 14 c# multithreading mutex

如何创建系统/多进程Mutex以使用相同的非托管资源协调多个进程.

背景:我编写了一个使用文件打印机的程序,一次只能由一个进程使用.如果我想在计算机上运行的多个程序上使用它,我需要一种在整个系统中同步它的方法.

Lim*_*ent 29

您可以使用System.Threading.Mutex类,该类具有OpenExisting方法来打开命名系统互斥锁.

这不回答这个问题:

如何创建系统/多进程互斥锁

要创建系统范围的互斥锁,请调用System.Threading.Mutex构造函数,该构造函数将字符串作为参数.这也称为"命名"互斥锁.要查看它是否存在,我似乎找不到比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.
}
Run Code Online (Sandbox Code Playgroud)

现在,要成为一名优秀的程序员,您需要在结束程序时释放此互斥锁

_mutey.ReleaseMutex();
Run Code Online (Sandbox Code Playgroud)

或者,你可以保留它,在这种情况下,当你的线程退出时它将被称为'废弃',并允许另一个进程创建它.

[编辑]

作为描述被放弃的互斥锁的最后一句话的旁注,当另一个线程获取互斥锁时,System.Threading.AbandonedMutexException将抛出异常,告诉他在被抛弃的状态下找到它.

[编辑二]

我不知道为什么几年前我就回答了这个问题; 有(并且是)一个构造函数重载,它更好地检查现有的互斥锁.事实上,我提供的代码似乎有竞争条件!(并且因为没有纠正我而感到羞耻!:-P)

这是竞争条件:想象两个进程,它们都试图同时打开现有的互斥锁,并且都进入代码的catch部分.然后,其中一个过程创建了互斥体,并且从此过上幸福的生活.但是,另一个进程尝试创建互斥锁,但这次它已经创建了!检查/创建互斥锁需要是原子的.

http://msdn.microsoft.com/en-us/library/bwe34f1k(v=vs.90).aspx

所以...

var requestInitialOwnership = false;
bool mutexWasCreated;
Mutex m = new Mutex(requestInitialOwnership, 
         "MyMutex", out mutexWasCreated);
Run Code Online (Sandbox Code Playgroud)

我认为这里的诀窍是看起来你有一个你实际上没有的选项(看起来像我的设计缺陷).如果您发送true,有时无法判断您是否拥有互斥锁requestInitialOwnership.如果您通过true并且看起来您的呼叫创建了互斥锁,那么显然您拥有它(由文档确认).如果你通过true并且你的调用没有创建互斥锁,你只知道互斥锁已经创建,你不知道是否有一些其他进程或线程可能创建了互斥锁当前拥有互斥锁.所以,你必须WaitOne确保你拥有它.但那么,Release你做了多少次?如果其他进程在获得它时拥有互斥锁,那么只WaitOne需要显式调用Released.如果您对构造函数的调用导致您拥有互斥锁,并且您WaitOne明确调用,则需要两个Releases.

我会把这些单词写进代码:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

由于我没有看到测试您当前是否拥有互斥锁的方法,我强烈建议您传递false给构造函数,以便您知道自己没有互斥锁,并且知道要调用多少次Release.

  • 只是一个小的(但很重要的)细节,当线程而不是进程结束时,Mutex被放弃了.在我的情况下,我有一个带有多个线程的WCF服务,其中一个是放弃互斥锁,允许多个实例同时运行.请参阅http://msdn.microsoft.com/en-us/library/system.threading.abandonedmutexexception.aspx (3认同)