【问题标题】:Cross-process mutex instantiation跨进程互斥体实例化
【发布时间】:2020-05-05 23:55:44
【问题描述】:

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

谢谢。

【问题讨论】:

    标签: c# .net concurrency mutex


    【解决方案1】:

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

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

    还有an overload接受三个参数:

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

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

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

    【讨论】:

    • 好吧,可能更聪明的方法是创建Mutex,然后尝试WaitOne 并查看boolean 结果?
    • @VRoxa 是的,使用 millisecondsTimeout 参数的零值调用 WaitOne 无疑是一个灵活的选择!
    • 只是为了完成。作为对文档引用的回应...在我在上面的第一个示例中创建Mutex 时,我完全确定我可以创建命名为Mutex,不是吗?所以,这符合我的上下文。
    • 我认为您的代码在mutex = Mutex.OpenExisting(APP_NAME)mutex = new Mutex(true, APP_NAME) 行之间存在竞争条件。同时,另一个进程可以创建并获取互斥锁的所有权。机会很小,但我绝对不会让这段代码在生产环境中运行。
    【解决方案2】:

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

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

    我如何释放一个在我创建时最初并不拥有的Mutex

    这个问题的答案很简单:只需在您创建 Mutex 之后获取它。然后你就可以释放它了。

    而且,如果我将参数 initiallyOwned 设置为 false,那么谁真正拥有该 Mutex?

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-07-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-11
      • 1970-01-01
      • 2016-12-27
      • 1970-01-01
      相关资源
      最近更新 更多