简体   繁体   English

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

[英]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. 如何创建系统/多进程Mutex以使用相同的非托管资源协调多个进程。

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. 如果我想在计算机上运行的多个程序上使用它,我需要一种在整个系统中同步它的方法。

You can use the System.Threading.Mutex class, which has an OpenExisting method to open a named system mutex. 您可以使用System.Threading.Mutex类,该类具有OpenExisting方法来打开命名系统互斥锁。

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. 要创建系统范围的互斥锁,请调用System.Threading.Mutex构造函数,该构造函数将字符串作为参数。 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: 要查看它是否存在,我似乎找不到比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. 作为描述被放弃的互斥锁的最后一句的旁注,当另一个线程获取互斥锁时,将抛出异常System.Threading.AbandonedMutexException告诉他在被遗弃的状态下找到它。

[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 ) (并且因为没有纠正我而感到羞耻!:-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. 这是竞争条件:想象两个进程,它们都试图同时打开现有的互斥锁,并且都进入代码的catch部分。 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 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 . 如果您对requestInitialOwnership发送true ,有时您无法判断您是否拥有互斥锁。 If you pass true and it appears that your call created the mutex, then obviously you own it (confirmed by documentation). 如果你传递了true并且看起来你的调用创建了互斥锁,那么显然你拥有它(由文档确认)。 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. 如果你传递了true并且你的调用没有创建互斥锁,那么你所知道的是互斥锁已经创建了,你不知道是否有一些其他进程或线程可能创建了互斥锁当前拥有互斥锁。 So, you have to WaitOne to make sure you have it. 所以,你必须要WaitOne以确保你拥有它。 But then, how many Release s do you do? 但是,你做了多少次Release If some other process owned the mutex when you got it, then only your explicit call to WaitOne needs to be Release d. 如果其他进程拥有互斥锁,那么只有您对WaitOne的显式WaitOne需要是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. 如果您对构造函数的调用导致您拥有互斥锁,并且您明确调用了WaitOne ,那么您将需要两个Release

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

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

I have not had good luck using the System Mutex described above using Mono under Linux. 我在Linux下使用Mono使用上面描述的System Mutex并没有好运。 I'm probably just doing something simple wrong but the following works well and cleans up nicely if the process exits unexpectedly (kill -9 ). 我可能只是做了一些简单的错误,但是如果进程意外退出(kill -9),以下工作很好并且可以很好地清理。 Would would be interested to hear comments or critisisms. 会有兴趣听到评论或批评。

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;

    }
}

without seeing your code it is tough to give specific advise but there is a mutex class in c# 没有看到你的代码很难给出具体的建议,但c#中有一个互斥类

MSDN MSDN

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM