跨进程互斥体实例化

Cross-process mutex instantiation

刚刚编写了一个必须一次处理一次的简单程序,因此通过使用具有特定名称的键控 Mutex 来实现。
代码(简化)如下所示。

static readonly string APP_NAME = "MutexSample";

static void Main(string[] args)
{
    Mutex mutex;
    try
    {
        mutex = Mutex.OpenExisting(APP_NAME);
        // At this point, with no exception,
        // the Mutex is acquired, so there is another
        // process running
        // Environment.Exit(1); or something
    }
    catch (WaitHandleCannotBeOpenedException)
    {
        // If we could not acquire any mutex with
        // our app name, let's create one
        mutex = new Mutex(true, APP_NAME);
    }

    Console.ReadKey(); // Just for keeping the application up
    // At some point, I just want to release
    // the mutex
    mutex.ReleaseMutex();
}

我的第一次尝试是像 new Mutex(false, APP_NAME) 一样实例化 Mutex,但是调用 mutex.ReleaseMutex() 时抛出异常

System.ApplicationException: 'Object synchronization method was called from an unsynchronized block of code.'

刚刚注意到构造函数的第一个参数(initiallyOwned)标记了创建Mutex的当前线程是否拥有它,不出所料,一个线程不能释放一个Mutex 不属于该线程。

因此将此参数更改为 true 解决了该问题,如上面的代码所示。

嗯,我的问题是,该参数的全部意义是什么?我的意思是,我什么时候需要创建一个我无法发布的 Mutex
而且,如果我将参数 initiallyOwned 设置为 false,谁真正拥有 Mutex

谢谢。

when will I need to create a Mutex that I am not able to release it.

这个问题实在太宽泛了。但一个不太广泛的问题是:

How could I release a Mutex that wasn't initially owned when I create it?

答案很简单:只需在创建 Mutex 之后获取它。然后就可以释放了。

And, if I set the parameter initiallyOwned to false, who does really own that Mutex?

这取决于 Mutex 是否已被其他线程或进程创建和获取。如果不是,则 没有人 拥有它,您的代码稍后将能够获取它。

当然,对于你所处理的场景,你甚至不一定想要获得Mutex。通常的方法是尝试 创建 Mutexthis constructor。如果您的代码实际创建了 Mutex,则将设置第三个参数。您实际上永远不需要获取它;您只是在使用 OS 将确保 Mutex 只创建一次的事实。

请注意,已经有很多关于使用 .NET 编写单实例程序的非常好的建议。我强烈建议您查看此处找到的信息:
What is the correct way to create a single-instance WPF application?
How to restrict a program to a single instance

没有人拥有 Mutex,除非有人通过调用它的方法 WaitOne. Passing initiallyOwned: true is an attempt to acquire immediately a newly created Mutex, but it's problematic. From the documentation:

You should not use this constructor to request initial ownership, unless you can be certain that the thread will create the named mutex.

还有an overload接受三个参数:

public Mutex (bool initiallyOwned, string name, out bool createdNew);

...但是创建没有初始所有权的 Mutex 更简单,然后在您准备好被阻止时获取它(以防它恰好被其他人获取)。

mutex = new Mutex(initiallyOwned: false, APP_NAME);
mutex.WaitOne(); // Potentially blocking