如何创建系统/多进程Mutex以使用相同的非托管资源协调多个进程。
背景: 我编写了一个使用文件打印机的程序,一次只能由一个进程使用。如果我想在计算机上运行的多个程序上使用它,我需要一种在整个系统中同步它的方法。
答案 0 :(得分:28)
您可以使用System.Threading.Mutex类,该类具有OpenExisting方法来打开命名系统互斥锁。
这不回答这个问题:
如何创建系统/多进程Mutex
要创建系统范围的互斥锁,请调用以字符串作为参数的System.Threading.Mutex构造函数。这也称为“命名”互斥锁。为了查看它是否存在,我似乎找不到比尝试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();
或者,您可以保留它,在这种情况下,当您的线程退出时它将被称为'废弃',并允许其他进程创建它。
[编辑]
作为描述被放弃的互斥锁的最后一句话的旁注,当另一个线程获取互斥锁时,将抛出异常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);
我认为这里的诀窍是看起来你有一个你实际上没有的选项(看起来像我的设计缺陷)。如果您为true
发送requestInitialOwnership
,则有时无法判断您是否拥有互斥锁。如果您通过true
并且您的呼叫似乎创建了互斥锁,那么显然您拥有它(由文档确认)。如果你通过true
并且你的调用没有创建互斥锁,那么你只知道互斥锁已经创建了,你不知道是否有一些其他进程或线程可能创建了互斥锁当前拥有互斥锁。因此,您必须WaitOne
以确保拥有它。但是,你做了多少Release
?如果某个其他进程拥有互斥锁,那么只有您对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
的次数。
答案 1 :(得分:3)
您可以使用System.Threading.Mutex
类,它具有OpenExisting
方法来打开命名系统互斥锁。
答案 2 :(得分:0)
没有看到你的代码就很难给出具体的建议但c#中有一个互斥类
答案 3 :(得分:0)
我在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;
}
}