2

I understand that Mutex can be used to allow only one instance of my app starting on a single machine. This means that no matter how many desktops are used by an arbitrary number of users, there can be at most one instance of the program running.

Now, instead of only allowing one instance, I want to allow for at most two, nothing more. How to do it? I tried code such as this:

    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;

    }

The above code works... sort of. It works in all the cases I have tested except this one:

  1. Open the program( let's call it p1)
  2. Open the program again ( let's call it p2)
  3. Close p1.
  4. Open the program a third time ( p3)
  5. Expectation: during p3 , the above method should return a true ( because createNew1 should be true), but it returns a false ( because createNew1 returns false).

Why is this so? Any idea how to fix this?

Community
  • 1
  • 1
Graviton
  • 81,782
  • 146
  • 424
  • 602

4 Answers4

1

What you want is a semaphore, not a mutex. A mutex handles mutual exclusion, a semaphore restricts the use of a shared resource to a maximum number.

Chris Latta
  • 20,316
  • 4
  • 62
  • 70
  • The problem with semaphores is that you have to manually release them. If one of your two instances gets killed without releasing the semaphore, you won't be able to restart it. – Gabe Jun 29 '12 at 03:55
  • For semaphore, what if different users use remote desktop program ( like Citrix) to login to the same machine at the same time? Will the semaphore handles them as if one user is opening multiple instances of the program? – Graviton Jun 29 '12 at 03:56
  • Semaphore is not usable if you want to restrict the total number of applications launched-- it is only usable if you want to restrict the number of resources within an application. – Graviton Jun 29 '12 at 07:01
0

This is because in p2 you open the first mutex again. This mutex stays open because p2 keeps it so. When you open the first mutex and find it was already open, you should close it so p2 only keeps the second mutex open and p1 only keeps the first mutex open.

Polity
  • 14,734
  • 2
  • 40
  • 40
0

Simple. You are mistaking the point of the out parameter (createdNew). From the docs:

When this method returns, contains a Boolean that is true if a local mutex was created (that is, if name is null or an empty string) or if the specified named system mutex was created; false if the specified named system mutex already existed. This parameter is passed uninitialized.

In your case, p2 has already created the first mutex, so it isn't "created new".

What you want to do is not rely on the application's creation of the mutex, but instead rely on owning the mutex. Try passing true as the first argument, and calling ReleaseMutex when the application exits.

Alternatively, switch to a named semaphore as @ChrisLatta suggests.

Chris Shain
  • 50,833
  • 6
  • 93
  • 125
0

What Chris Shain said is correct. What you need to do is to OWN the mutex, not just creating it. Also, you MUST manually release the mutex when exiting the application, otherwise other application instances may encounter an AbandonedMutexException.

Below is a simple code example of how you might want to implement it. Note that this particular code requires the StartInstance() and StopInstance() to be called by the same thread.

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();
}

EDIT : Actually, if you want to use createNew as a way to detect multiple instances, you probably can do that, but I personally don't recommend it since Mutex is not designed for that.

However, even if you decide to use the createNew methodology, you will still need to explicitly close the mutex yourself once your application exits.

One advantage that this methodology may have over the previous one is that the Close() method does not have to be called by the same thread that creates it.

Below is a simple code example employing the createNew methodology. Note that it is not thread-safe. You will need to use lock() in StartInstance() and StopInstance() to make it thread-safe.

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();
}
SF Lee
  • 1,767
  • 4
  • 17
  • 32