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

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

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

您可以使用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. } 

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

 _mutey.ReleaseMutex(); 

或者,您可以保留它,在这种情况下,当您的线程退出时,它将被称为“废弃”,并允许其他进程创建它。

[编辑]

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

[编辑二]

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

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

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); 

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

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

 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(); } } 

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

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

没有看到你的代码很难给出具体的建议,但c#中有一个互斥类

MSDN

我在Linux下使用Mono使用上面描述的System Mutex并没有好运。 我可能只是做了一些简单的错误,但是如果进程意外退出(kill -9),以下工作很好并且可以很好地清理。 会有兴趣听到评论或批评。

 class SocketMutex{ private Socket _sock; private IPEndPoint _ep; public SocketMutex(){ _ep = new IPEndPoint(IPAddress.Parse( "127.0.0.1" ), 7177); _sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); _sock.ExclusiveAddressUse = true; // most critical if you want this to be a system wide mutex } public bool GetLock(){ try{ _sock.Bind(_ep); // 'SocketException: Address already in use' }catch(SocketException se){ Console.Error.WriteLine ("SocketMutex Exception: " se.Message); return false; } return true; } }