2

Just wrote a simple program that must be processed once at a time, so achieved this by using a keyed Mutex with a particular name.
The code (simplified) looks like this.

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

My first attempt was instantiating the Mutex like new Mutex(false, APP_NAME), but calling mutex.ReleaseMutex() was throwing an exception

System.ApplicationException: 'Object synchronization method was called from an unsynchronized block of code.'

Just noticed that the first parameter of the constructor (initiallyOwned) marks whether the current thread that is creating the Mutex owns it and, unsurprisingly, a thread cannot release a Mutex which is not owned by that thread.

So changing this parameter to true fixed that issue, as shown on the code above.

Well, my question is, what is the whole point of that parameter? I mean, when will I need to create a Mutex that I am not able to release it.
And, if I set the parameter initiallyOwned to false, who does really own that Mutex?

Thanks.

VRoxa
  • 973
  • 6
  • 25

2 Answers2

2

Nobody owns a Mutex, unless it's acquired by somebody by calling its method WaitOne. Passing initiallyOwned: true is an attempt to acquire immediately a newly created Mutex, but it's problematic. From the documentation:

You should not use this constructor to request initial ownership, unless you can be certain that the thread will create the named mutex.

There is also an overload that accepts three parameters:

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

...but it's simpler to just create the Mutex without initial ownership, and later acquire it when you are ready to be blocked (in case it happens to be acquired by someone else).

mutex = new Mutex(initiallyOwned: false, APP_NAME);
mutex.WaitOne(); // Potentially blocking
Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
  • Well, may be a smarter way to do the same would be actually create the `Mutex` and then try to `WaitOne` and peek into the `boolean` result? – VRoxa May 08 '20 at 17:46
  • @VRoxa yeap, calling `WaitOne` with a zero value for the `millisecondsTimeout` argument is certainly a flexible option! – Theodor Zoulias May 08 '20 at 18:04
  • Just for the sake of completion. In response of the documentation quote... At the point I am creating the `Mutex` on my first example above, I am completely sure I can create the named `Mutex`, ain't I? So, that would fit in my context. – VRoxa May 08 '20 at 18:09
  • I think that your code has a race condition between the lines `mutex = Mutex.OpenExisting(APP_NAME)` and `mutex = new Mutex(true, APP_NAME)`. Another process could create and acquire the ownership of the mutex in the meanwhile. The chances are small, but I would definitely not feel comfortable having this code running in the production environment. – Theodor Zoulias May 08 '20 at 18:37
1

when will I need to create a Mutex that I am not able to release it.

That's really too broad a question. But a less broad question would be:

How could I release a Mutex that wasn't initially owned when I create it?

And the answer to that is easy: just acquire the Mutex after you create it. Then you can release it.

And, if I set the parameter initiallyOwned to false, who does really own that Mutex?

That depends on whether the Mutex was already created and acquired by some other thread or process. If it wasn't, then no one owns it and your code would be able to acquire it later.

Of course, for the scenario you're dealing with, you don't necessarily even want to acquire the Mutex. The usual approach is to try to create the Mutex with this constructor. The third parameter will be set if your code actually created the Mutex. You never actually need to acquire it; you're just using the fact that the OS will ensure that the Mutex is only ever created once.

Note that there is already a lot of really good advice about writing single-instance programs with .NET. I strongly recommend you review the information found here:
What is the correct way to create a single-instance WPF application?
How to restrict a program to a single instance

Peter Duniho
  • 68,759
  • 7
  • 102
  • 136