1

I don't understand why the .NET mutex does not either throw an AbandonedMutexException in one of the waiting threads or release the mutex when Mutex.Dispose() is called.

In particular, code like this will deadlock:

public static void testCall()
{
    using (var mutex = new System.Threading.Mutex(false, "testname"))
    {
        mutex.WaitOne();
        Console.WriteLine("second call");
    }
}

public static void Main(string[] args)
{
    var thread = new System.Threading.Thread(testCall);
    using (var mutex = new System.Threading.Mutex(false, "testname"))
    {
        mutex.WaitOne();
        Console.WriteLine("first call");
        thread.Start();
        System.Threading.Thread.Sleep(new TimeSpan(0, 0, 5));
        Console.WriteLine("sleep done");
    }

    thread.Join();
}

Mind you, I understand the AbandonedMutexException usually comes from the underlying WIN32 mutex and in native code would only be triggered in case the owning thread dies - I've been writing C/C++ code for a long time and am fully aware of the underlying design. I also know that the following code is an easy workaround:

using (var mutex = new System.Threading.Mutex(false, "testname"))
{
    mutex.WaitOne();
    try
    {
        Console.WriteLine("first call");
        thread.Start();
        System.Threading.Thread.Sleep(new TimeSpan(0, 0, 1));
        Console.WriteLine("sleep done");
    }
    finally
    {
        mutex.ReleaseMutex();
    }
}

What I don't understand is the rationale behind .NET mutexes not forcing a release when the object has been explicitly disposed of while holding the lock. Wouldn't that be more in-line with the rest of the .NET programming paradigm? If/when the developer explicitly destroys a locked mutex... it only makes sense to mark it as abandoned.

Mahmoud Al-Qudsi
  • 28,357
  • 12
  • 85
  • 125

1 Answers1

2

You probably don't want it to work the way that you suggest. Let's say you have this:

using (var m = new Mutex(....))
{
    m.WaitOne();
    // do some stuff here
    // that ends up throwing an exception
}

The exception is thrown while your thread holds the mutex. If the mutex were released as part of the dispose, then some other thread could obtain the mutex and begin partying on the data that you were updating. Except that now the data is in an unknown (probably inconsistent or corrupt) state.

It's best, of course, to handle the exception and clean things up, but absent that I'd rather the mutex remain held (or abandoned if the thread dies) so that the next thread that tries to acquire the mutex knows that something bad happened.

In addition to the above, adding automatic release would require that the .NET wrapper keep track of which thread owns the mutex. And the Dispose method would have to check that value to determine if it should call ReleaseMutex. And it's just not possible to keep track of that. The .NET program could pass the mutex handle to some unmanaged code, which could acquire or release the mutex without the wrapper's knowledge.

So, the answer is twofold: First, it's not possible. Second, even if it were possible, you probably don't want that behavior.

Jim Mischel
  • 131,090
  • 20
  • 188
  • 351
  • I disagree. If the code does not handle the exception, the appropriate behavior would be to throw an `AbandonedMutexException` because the code that locked the mutex lost it due to unintended behavior (the exceptions). I agree, `ReleaseMutex()` is both unwise and a little overboard, but `AbandonedMutexException` makes sense. – Mahmoud Al-Qudsi Apr 13 '12 at 22:08
  • But if the thread doesn't exit, then the mutex isn't abandoned. – Jim Mischel Apr 13 '12 at 23:12
  • No, not in the WIN32 meaning of abandoned.. but wouldn't you say in your example if an exception is thrown and not handled *and* the mutex is disposed, that it would not be incorrect to consider the mutex "abandoned?" – Mahmoud Al-Qudsi Apr 13 '12 at 23:16
  • 1
    Yes, I would consider the mutex "abandoned." But the underlying object is a WIN32 mutex, which is only "abandoned" if the thread dies while it still has a lock on the mutex. If the thread doesn't die, no abandoned mutex. And we've already established that it's unwise and probably not possible to release the mutex, so we're stuck with the existing behavior. – Jim Mischel Apr 13 '12 at 23:46