14

Why would the following structure cause an AbandonedMutexException. Even if there is an error or method returns. The mutex is being released.

static Mutex WriteMutex = new Mutex(false, @"Global\mutex2203");

public static void Demo()
{

    try
    {
        WriteMutex.WaitOne();

        //rest of coding stuff here
    }
    finally
    {
            WriteMutex.ReleaseMutex();
    }

}

Receives reports cant regenerate the bug.

Edit: The exception occurs at WriteMutex.WaitOne(); no other code. And only this method touches that mutex.

J. Doe
  • 157
  • 1
  • 1
  • 10
  • I was using the application GUID to simulate single instance. Somehow the internal code also use the GUID to create a Mutex. Fixed altering my GUID to be more 'unique', – fcm Sep 11 '19 at 20:19

4 Answers4

11

An AbandonedMutexException is thrown when one thread acquires a Mutex object that another thread has abandoned by exiting without releasing it (see AbandonedMutexException). The code you cite in your question would not necessarily be the code that is causing the exception, only "receiving" it (i.e. detecting the situation that throws the exception).

That is, code in another thread (could be the same method but is likely not) acquires the Mutex but does not release it and permits its thread to exit without the Mutex ever being released. Then the thread running the code you show above throws the exception when it attempts to acquire the Mutex.

Ken Clement
  • 748
  • 4
  • 13
  • Can you please give an example of thread being exit without calling finally block ? – J. Doe Dec 31 '15 at 03:15
  • @J.Doe, I'm not entirely sure what you mean by your question. The issue here is that a previous thread executed a `WaitOne` on mutex `Global\mutex2203` and exited without first executing a `ReleaseMutex` on that same mutex. When another thread attempted to do a `WaitOne` on that mutex, the `AbandonedMutexException` was thrown because the mutex was owned by a nonexistant thread. This indicates a coding error. For a more complete explanation of mutexes, see: https://msdn.microsoft.com/en-us/library/hw29w7t1(v=vs.110).aspx. Please clarify if you still have a question. – Ken Clement Dec 31 '15 at 05:21
  • @J.Doe, I'm still not sure of the relevance of your prior question to the current topic or my answer, but @Mike Nakis does provide an example of a thread that exits without calling the finally block (or at least giving it a chance to do anything): `static int Main( string[] arguments ) { try { return arguments[1000].Length; } finally { System.Console.WriteLine( "you will never see this!" ); } }` I verified that in fact the output never makes it to the screen. – Ken Clement Dec 31 '15 at 05:47
  • But how can a thread exited in the middle of code ? I'm not even calling abort() or anything ? and how its a coding error if thread is dying itself ? I have put release mutex inside finally block so it suppose to be called even there is an exception. – J. Doe Dec 31 '15 at 06:09
  • If the example you provide wont be calling the finally block, isnt it a huge bug ? – J. Doe Dec 31 '15 at 06:11
  • @J.Doe, A thread can exit whenever it is too damaged to continue. Managed code greatly but not entirely reduces the incidence of this. The pending finally blocks may or may not execute in such a situation. I suspect this is not about finally block execution in your case. Have you looked at each usage of that mutex in your code and have you verified that you are always releasing the mutex? Think horses not zebras - the cause of the problem is probably something mundane not exotic. – Ken Clement Dec 31 '15 at 06:36
  • In the example I provided, one merely need cut and paste the code into a console app project in visual studio and execute it. That's what I did to verify @Mike Nakis 's example. It is not a huge bug or any bug at all. Finally block execution happens under nominal execution and well behaved exceptions. If a thread is sufficiently damaged then we are in the area of undefined behavior and all bets are off. One could also write an `unsafe` method that corrupts the execution stack so that immediate termination is all that's possible - no finally blocks would be executed then either. – Ken Clement Dec 31 '15 at 06:42
  • that mutex is only used in that method, nowhere else. Wrapping try catch around the WaitOne seems to be the only possible solution. – J. Doe Dec 31 '15 at 09:18
  • Without knowing what `//rest of coding stuff here` consists of or the general flow of your application I can't help you further. Wrapping the `WaitOne` call ought to suppress the behavior but it will not address the underlying flaw in code or assumptions made elsewhere that gives rise to this thrown exception. I recommend you track this as technical debt. – Ken Clement Dec 31 '15 at 16:41
  • rest of code is nothing much but to append a string in a file. I removed it to make code look more clear to understand the question. – J. Doe Jan 01 '16 at 08:59
  • I recommend you work-up a version of your code, reduced as much as possible such that it still produces the behavior. I figure one of two things will happen: 1) You will discover the problem yourself. 2) You will post this reduced code to SO and somebody else will run your program, verify the problem exists (by reproducing it), and explain the problem you are having or lead you to discover it yourself. In any event it is worth trying to solve this problem and learn from the experience than simply suppress the behavior - all the good developers do the former and avoid the later. – Ken Clement Jan 01 '16 at 20:45
  • The problem is, its working fine at dev end, or on all the PCs I tested. Not once I got that error. But I receives the bug reports from users. Currently there is no way to reproduce this error at development side. – J. Doe Jan 04 '16 at 11:35
  • Given that, I'd say that you have something funny going on with another process thread on your customer systems acquiring that mutex and then terminating before before releasing it. You can either switch to a `\Local` mutex or if that breaks something use the pattern pointed out by @CraigM and in the SO question titled "What is a good pattern for using a Global Mutex in C#" (link below in @CraigM's answer) – Ken Clement Jan 05 '16 at 02:36
2

Where is the exception occurring? Does it happen when you do WriteMutex.WaitOne();?

If so, there must be something (presumably not in the code you posted) that takes ownership of it, then exits happening before you get the exception.

Using async methods could also be a problem with code using Mutexes due to swapping the threads around. Make sure you aren't using any of that stuff in a non-compatible way.

Also, be aware that named mutexts are not local to your application: other processes could be screwing with it (and the problem could be there). If you want something local, don't give it a name, or even better use something more efficient and less error prone like the lock keyword for such cases.

Some nice details about using Mutex properly (and avoiding issues like you seem to have) are here: What is a good pattern for using a Global Mutex in C#?

CraigM
  • 389
  • 2
  • 5
  • Yes exception is occurring right on WriteMutex.WaitOne();. There is no other method that touches that mutex. The reason mutex is being used because of multiple process of application can be running so lock must be system wide. – J. Doe Dec 31 '15 at 03:13
  • Assuming you don't have anything funny going on in anther process (some unrelated application that happens to use the same mutex for example) then this is beyond what I know. I don't think I can help much if it wasn't any of the other things I mentioned. Good luck! – CraigM Dec 31 '15 at 03:30
1

You must also call WriteMutex.Dispose() in the finally block, but it is better to use a using block. Try to use this pattern: https://stackoverflow.com/a/229567/2185689

Sergey
  • 11
  • 1
0

For me, I was getting "The wait completed due to an abandoned mutex." warning because the console app was running under the Task Scheduler and the task scheduler was terminating it. That was not behavior I wanted.

I resolved it by going to the task in question, Editing the Trigger and and unchecking the "Stop task if it runs longer than:" option.

Note that there are other options that can cause the task to termination as well.

Conditions Tab : Power -> "Stop if the computer switches to battery power"

Settings Tab : "Stop the task if it runs longer than:"

Craig
  • 344
  • 4
  • 9