shansfk shansfk - 2 months ago 19
C# Question

Mutex under using block behaves differently

I was following this article regarding threading here. In that under section
Mutex the following code was there.

class OneAtATimePlease
{
static void Main()
{
// Naming a Mutex makes it available computer-wide. Use a name that's
// unique to your company and application (e.g., include your URL).

using (var mutex = new Mutex (false, "oreilly.com OneAtATimeDemo"))
{
// Wait a few seconds if contended, in case another instance
// of the program is still in the process of shutting down.

if (!mutex.WaitOne (TimeSpan.FromSeconds (3), false))
{
Console.WriteLine ("Another app instance is running. Bye!");
return;
}
RunProgram();
}
}

static void RunProgram()
{
Console.WriteLine ("Running. Press Enter to exit");
Console.ReadLine();
}
}


But when I run this the code is not behaving as expected, If I run the exe (the exe generated of the above) twice it should print "Another app instance is running. Bye!". But its not going to that block.

However if i remove the using block the code behaves correctly as expected.

Please help me. I am new to threading concepts.

UPDATE

Sorry for misleading. I actually didn't do like exactly written in that article.

My code as is,

internal class Program
{
/// <summary>
/// Entry point
/// </summary>
/// <param name="args">The arguments.</param>
internal static void Main(string[] args)
{
//Misc.RunAssemblies();

var threadingDemo = new ThreadingDemo();
threadingDemo.MutexDemo();

Console.ReadLine();
}
}

namespace LearnNet.Console
{
using System.Threading;

public class ThreadingDemo
{
public void MutexDemo()
{
using (var mutex = new Mutex(false, "Global\\oreilly.com OneAtATimeDemo"))
{
// Wait a few seconds if contended, in case another instance
// of the program is still in the process of shutting down.
if (!mutex.WaitOne(0, false))
{
System.Console.WriteLine("Another app instance is running. Bye!");
return;
}

RunProgram();
}
}

static void RunProgram()
{
System.Console.WriteLine("Running. Press Enter to exit");
}
}
}


This reproduces the issue which i explained above. And if i remove the using block it behaves correctly.

Evk Evk
Answer

You have to understand how mutex works. WaitOne acquires it and ReleaseMutex or Disposing it releases it. At the end of using block (when control flow leaves it), mutex is Disposed (that's why using block exists in the first place), and so is released. In your updated code, mutex is acquired and then immediatly released after RunProgram statement, and any subsequent instances also acquire and release it immediatly.

When you don't use using block, you don't Dispose mutex and so don't release the mutex. When Console.ReadLine statement executes - process still holds mutex. When your process ends, mutex is still released, but it's not very good practice - better always release mutex explicitly.

As for why it works in the first code you posted (before update) - there Console.ReadLine() statement is inside using block, and so when control flow blocks on this statement - process still holds the mutex.

Comments