Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# ReleaseMutex() is not releasing mutex in multiple instances of console application while launching from Visual Studio

I have written a sample console application which creates a mutex as shown in below code sample. I am launching this application directly from Visual Studio (VS2013) by pressing Ctrl + F5 (running the application without debugger). For the 1st instance of console application I acquire the mutex and the following line is displayed in console:

New Instance created...

However, when I create a second instance of console application using Ctrl + F5 again, I get the following message in the console:

Instance already acquired...

even though I explicitly release mutex after 500ms with this line of code:

mut.ReleaseMutex();

In the same thread which acquires the mutex, I still see that my second instance of console application waits for the mutex to be released.

Can someone explain to me why is it so or correct me if I am doing something wrong? If I understand, ReleaseMutex should release the mutex from the same thread which acquires it via mut.WaitOne(0) call so that any other thread waiting to acquire mutex should be provided ownership. However, in this case I am not able to see it working.

If I close the 1st instance which acquired mutex (still my second is alive) and try to launch a 3rd instance with Ctrl+F5, I can see that there is an AbandonedMutexException:

Unhandled Exception: System.Threading.AbandonedMutexException: The wait completed due to an abandoned mutex.

PS: Interestingly I can see that this works fine if I pass false in mutex constructor as

static Mutex mut = new Mutex(false, "Global\\test");

What's the significance of initiallyOwned parameter in the

public Mutex(bool initiallyOwned, string name);

constructor version of mutex class?

Console output for 2 instances run from VS

class Program
{
    static Mutex mut = new Mutex(true, "Global\\test");

    static void Main(string[] args)
    {

        if (IsInstance())
        {
            Console.WriteLine("New Instance created...");
        }
        else
        {
            Console.WriteLine("Instance already acquired...");
        }

        Console.ReadLine();
    }
    static bool IsInstance()
    {
        if (!mut.WaitOne(0))
        {
            Console.WriteLine("Thread id {0} Waiting at Mutex...",AppDomain.GetCurrentThreadId());
            return false;
        }
        else
        {
           Console.WriteLine("Thread id {0} got Mutex...", AppDomain.GetCurrentThreadId());
           Thread.Sleep(500);
           mut.ReleaseMutex();
           return true;
        }
    }

}
like image 882
Alby Avatar asked Feb 16 '17 13:02

Alby


People also ask

What is the full name of C?

In the real sense it has no meaning or full form. It was developed by Dennis Ritchie and Ken Thompson at AT&T bell Lab. First, they used to call it as B language then later they made some improvement into it and renamed it as C and its superscript as C++ which was invented by Dr.

What do you mean by C?

C is a structured, procedural programming language that has been widely used both for operating systems and applications and that has had a wide following in the academic community. Many versions of UNIX-based operating systems are written in C.

Is C language easy?

C is a general-purpose language that most programmers learn before moving on to more complex languages. From Unix and Windows to Tic Tac Toe and Photoshop, several of the most commonly used applications today have been built on C. It is easy to learn because: A simple syntax with only 32 keywords.

What is C language used for?

C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...


1 Answers

So to understand a problem you need to know about two things:

  1. How initiallyOwned parameter works
  2. Mutex reentrancy (recursive calls).

If you create Mutex with initiallyOwned = true - it will try to immediately acquire ownership BUT only if such mutex is not already created. So the first instance of your application immediatly acquires ownership of the mutex. It's about the same as doing:

 var mut = new Mutex(false, "Global\\test");
 mut.WaitOne();

If this mutex already exists, it will not try to acquire ownership. To see if mutex was created (and so, it you already own it), you can use this overload:

bool createdNew;
mut = new Mutex(true, "Global\\test", out createdNew);

Now, Mutex allows several calls to WaitOne and ReleaseMutex, from the same thread. If you called WaitOne multiple times - you need to call ReleaseMutex the same amount of times to release it. However, for your first instance, you call WaitOne twice: first because of initiallyOwned parameter (and because mutex does not exists yet and is created), and second time you call it explicitly. But you only call ReleaseMutex once, and as such your mutex is not released and is owned by first instance. When you close this instance - mutex is still not released and so becomes abandoned.

Here is a code example illustrating those points:

static Mutex mut;

static void Main(string[] args)
{
    bool createdNew;
    mut = new Mutex(true, "Global\\test", out createdNew);
    if (createdNew) {
        Console.WriteLine("New instance created with initially owned = true");
    }
    else if (IsInstance())
    {
        Console.WriteLine("New Instance created...");
    }
    else
    {
        Console.WriteLine("Instance already acquired...");
    }
    if (createdNew)
    {
        Thread.Sleep(500);
        mut.ReleaseMutex();
    }
    Console.ReadLine();

}
static bool IsInstance()
{
    if (!mut.WaitOne(0))
    {
        Console.WriteLine("Thread id {0} Waiting at Mutex...", AppDomain.GetCurrentThreadId());
        return false;
    }
    else
    {
        Console.WriteLine("Thread id {0} got Mutex...", AppDomain.GetCurrentThreadId());
        Thread.Sleep(500);
        mut.ReleaseMutex();            
        return true;
    }
}
like image 169
Evk Avatar answered Sep 30 '22 02:09

Evk