2

我了解Mutex 可用于仅允许我的应用程序的一个实例在一台机器上启动。这意味着无论任意数量的用户使用多少桌面,最多只能有一个程序实例在运行。

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

    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,上面的方法应该返回一个真(因为createNew1应该是true),但它返回一个假(因为 createNew1返回false)。

为什么会这样?知道如何解决这个问题吗?

4

4 回答 4

1

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

于 2012-06-29T03:43:43.570 回答
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();
}
于 2012-06-29T08:12:47.753 回答
0

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

于 2012-06-29T03:44:48.050 回答
0

简单的。您误解了 out 参数(createdNew)的要点。从文档

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

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

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

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

于 2012-06-29T03:45:29.953 回答