使用Mutex(??)来检查仅允许2个活动应用程序实例

时间:2012-06-29 03:36:17

标签: c# mutex semaphore

我理解Mutex can be used只允许我的应用的一个实例在一台计算机上启动。这意味着无论任意数量的用户使用了多少台桌面,最多只能运行一个程序实例。

现在,我不想只允许一个实例,而是希望最多允许两个,仅此而已。怎么做?我尝试过这样的代码:

    public static bool MutexChecking()
    {

            bool createNew1;
            // one set of GUID
            new Mutex(false, "54A8F2C1-6C11-4ED4-8A62-AD7C1D9F7970", out createNew1);



            if (createNew1)
                return true;
            bool createNew2;
             //another set
              new Mutex(false, "5E1C76D0-9897-412B-BD56-64A872F8FDE3", out createNew2);

            return createNew2;

    }

上面的代码有点......它适用于我测试的所有情况,除了这一个:

  1. 打开程序(让我们称之为p1
  2. 再次打开程序(让我们称之为p2
  3. 关闭p1
  4. 第三次打开该程序(p3
  5. 期望:在p3期间,上述方法应返回true(因为createNew1应为true),但它返回false(因为createNew1返回{{ 1}})。
  6. 为什么会这样?知道如何解决这个问题吗?

4 个答案:

答案 0 :(得分:1)

你想要的是信号量,而不是互斥量。互斥锁处理互斥,信号量将共享资源的使用限制为最大数量。

答案 1 :(得分:0)

这是因为在p2中你再次打开第一个互斥锁。这个互斥锁保持打开状态,因为p2保持打开状态。当你打开第一个互斥锁并发现它已经打开时,你应该关闭它,所以p2只保持第二个互斥锁打开而p1只保持第一个互斥锁打开。

答案 2 :(得分:0)

简单。你错了out参数的点(createdNew)。来自the docs

  

当此方法返回时,包含一个布尔值,如果是本地,则为true   创建了互斥锁(即,如果name为null或空字符串)或者是   创建了指定的命名系统互斥锁;如果指定则为false   命名系统互斥锁已经存在。传递此参数   初始化。

在您的情况下,p2已经创建了第一个互斥锁,因此它不是“新建的”。

您要做的不是依赖于应用程序创建互斥锁,而是依赖拥有互斥锁。尝试传递true作为第一个参数,并在应用程序退出时调用ReleaseMutex

或者,切换到@ChrisLatta建议的命名信号量。

答案 3 :(得分:0)

Chris Shain所说的是正确的。你需要做的是拥有互斥锁,而不仅仅是创建互斥锁。此外,您必须在退出应用程序时手动释放互斥锁,否则其他应用程序实例可能会遇到 AbandonedMutexException

以下是您可能希望如何实现它的简单代码示例。请注意,此特定代码要求相同的线程调用StartInstance()和StopInstance()。

private static Mutex Mutex1 = new Mutex(false, "54A8F2C1-6C11-4ED4-8A62-AD7C1D9F7970");
private static Mutex Mutex2 = new Mutex(false, "5E1C76D0-9897-412B-BD56-64A872F8FDE3");
private static Mutex AcquiredMutex;

public static bool StartInstance()
{
    if (AcquiredMutex != null)
        return true;

    if (Mutex1.WaitOne(1))
    {
        AcquiredMutex = Mutex1;
    }
    else if (Mutex2.WaitOne(1))
    {
        AcquiredMutex = Mutex2;
    }

    return (AcquiredMutex != null);
}

public static void StopInstance()
{
    if (AcquiredMutex != null)
        AcquiredMutex.ReleaseMutex();
}

编辑:实际上,如果您想使用 createNew 作为检测多个实例的方法,您可能会这样做,但我个人不建议这样做Mutex不是为此而设计的。

但是,即使您决定使用 createNew 方法,您仍需要在应用程序退出后自己明确地关闭互斥锁。

此方法可能比前一个方法具有的一个优点是,Close()方法不必由创建它的同一线程调用。

下面是一个使用 createNew 方法的简单代码示例。请注意,它不是线程安全的。您需要在StartInstance()和StopInstance()中使用lock()以使其成为线程安全的。

private static readonly string[] MutexNames = new string[]
{
    "54A8F2C1-6C11-4ED4-8A62-AD7C1D9F7970",
    "5E1C76D0-9897-412B-BD56-64A872F8FDE3"
};

private static Mutex CreatedMutex;

public static bool StartInstance()
{
    if (CreatedMutex != null)
        return true;

    foreach (string name in MutexNames)
    {
        bool created;
        Mutex mutex = new Mutex(false, name, out created);

        if (created)
        {
            CreatedMutex = mutex;
            return true;
        }
        else
        {
            mutex.Close();
        }
    }

    return false;
}

public static void StopInstance()
{
    if (CreatedMutex != null)
        CreatedMutex.Close();
}