跨进程互斥实例化



刚刚编写了一个必须一次处理一次的简单程序,因此通过使用具有特定名称的键控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

谢谢。

没有人拥有Mutex,除非它是由某人通过调用其方法WaitOne获得的。传递initiallyOwned: true是尝试立即获取新创建的Mutex,但这是有问题的。来自文件:

您不应该使用此构造函数来请求初始所有权,除非您可以确定线程将创建命名的互斥体。

还有一个接受三个参数的重载:

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

但更简单的做法是,在没有初始所有权的情况下创建Mutex,然后在准备被阻止时获取它(以防它碰巧被其他人获取(。

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

我什么时候需要创建一个无法发布的Mutex

这个问题太宽泛了。但一个不那么宽泛的问题是:

创建Mutex时,如何发布它?

答案很简单:只需在创建后获取Mutex。然后就可以发布它。

如果我将参数initiallyOwned设置为false,谁真正拥有Mutex?

这取决于Mutex是否已经由其他线程或进程创建和获取。如果不是,那么没有人拥有它,您的代码稍后可以获得它。

当然,对于您正在处理的场景,您甚至不一定想要获得Mutex。通常的方法是尝试使用此构造函数创建Mutex。如果您的代码实际创建了Mutex,则将设置第三个参数。你从来没有真正需要获得它;您只是在使用这样一个事实,即操作系统将确保Mutex只创建过一次。

请注意,关于用.NET编写单实例程序,已经有很多非常好的建议了。我强烈建议您查看此处的信息:
创建单实例WPF应用程序的正确方法是什么
如何将程序限制为单个实例

最新更新