T.Ben
T.Ben

Reputation: 21

C# Mutex always stuck on WaitOne

I have one process that creates the mutex and immediately takes ownership, and then when a button is clicked, it releases it:

Mutex req_mutex = new Mutex(true, "req_mutex");

...

req_mutex.WaitOne(); // not required for first click
req_mutex.ReleaseMutex();

The other process is looping and checking if the mutex exists, when it does it waits for it to be released:

bool waitingForReqMutexCreation = true;
while (waitingForReqMutexCreation)
{
      try
      {
           req_mutex = Mutex.OpenExisting("req_mutex", MutexRights.Synchronize);
           waitingForReqMutexCreation = false;
      }
      catch (WaitHandleCannotBeOpenedException)
      {
           Thread.Sleep(1000);
      }
}

...

req_mutex.WaitOne(); // wait for new request   *********** problem here *********
req_mem.readFile(); // read request
req_mutex.ReleaseMutex(); // release req mutex for more requests

the problem is that the WaitOne doesn't continue even after the mutex was supposed to be released by the button in the first process.

Does anyone have an idea why that may be?

Upvotes: 2

Views: 2320

Answers (3)

BurnsBA
BurnsBA

Reputation: 4929

You are basically acquiring the mutex twice in your first application. You can see this by killing your first application while the second one is running, and you'll get an AbandonedMutexException (which means the Mutex gets acquired). Reproduced with the following, readline instead of button clicks:

namespace Mutex_1
{
    class Program
    {
        static void Main(string[] args)
        {
            Mutex req_mutex = new Mutex(true, "req_mutex");

            String t = string.Empty;

            while (!t.Contains("q"))
            {
                Console.WriteLine("input: ");
                t = Console.ReadLine();

                Console.WriteLine("waiting for req_mutex");
                req_mutex.WaitOne(); // not required for first click
                Console.WriteLine("releasing req_mutex");
                req_mutex.ReleaseMutex();
            }

            Console.ReadLine();
        }
    }
}

namespace Mutex_2
{
    class Program
    {
        static void Main(string[] args)
        {
            Mutex req_mutex = null;

            bool waitingForReqMutexCreation = true;
            while (waitingForReqMutexCreation)
            {
                try
                {
                    req_mutex = Mutex.OpenExisting("req_mutex");
                    waitingForReqMutexCreation = false;
                }
                catch (WaitHandleCannotBeOpenedException)
                {
                    Console.WriteLine("req_mutex does not exist.");
                    Thread.Sleep(1000);
                }
            }
            Console.WriteLine("req_mutex found");
            req_mutex.WaitOne(); // wait for new request   *********** problem here *********
            Console.WriteLine("after req_mutex.WaitOne()");
            req_mutex.ReleaseMutex(); // release req mutex for more requests

            Console.ReadLine();
        }
    }
}

More evidence for this statement: calling ReleaseMutex twice in the parent will make things work on the first "click" (and crash the second time). You can fix this without throwing an exception by not acquiring the lock when it is created:

Mutex req_mutex = new Mutex(false, "req_mutex");

Upvotes: 2

Loonquawl
Loonquawl

Reputation: 1076

I think if you create the mutex with true (new Mutex(true, "req_mutex");) you so should not need to call WaitOne() in that process.

The documentation says it is better to specify false for initiallyOwned when calling this constructor overload. https://msdn.microsoft.com/en-us/library/f55ddskf(v=vs.110).aspx

EDIT: ahh, you beat me to it :) ...

Upvotes: 2

T.Ben
T.Ben

Reputation: 21

I think I found the answer to my own question...

Apparently the amount of WaitOne operations you do does matter. I took ownership (true argument in the constructor) and did an additional WaitOne in the same thread assuming that it won't hurt. Now in order to release the mutex I apparently had to call ReleaseMutex twice.

I guess I could still do it like this and call ReleaseMutex in a loop until an exception is thrown...

Upvotes: -1

Related Questions