Mutex and single instance console app ?

P

PL

I simply cannot get this to work with my current project, if I create a test
project
with only the code below it works fine but in my real app it still allows
two instances.

using System;
using System.Threading;

namespace MutexTest
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
Mutex appMutex = new Mutex(false, "Application");
if(appMutex.WaitOne(0, false))
{
System.Console.WriteLine("Running");
System.Console.ReadLine();
}
else
{
System.Console.WriteLine("App already running !");
}
}
}
}

The only difference between this test and my app is that I have more
code where I print the "Running" message, no other difference, still
it doesn't work !

I've read numerous other threads saying similar things but no solutions.
Could anyone shed some light as to why this does not work ?

Thank you
PL.
 
P

PL

This is amazing, I solved it by putting the appMutex variable outside main
and make it static, now it works as expected.

I assume it's because somehow the mutex is garbage collected and therefore
released before it should be.

This seems like a bug to me, I would assume the compiler does some strange
optimization here since it seem to work with the local variable in debug
mode.

PL.
 
W

Willy Denoyette [MVP]

No, this is not a bug in .NET, it's a "users bug". The JIT is free to mark
objects that are no longer referenced in the code path eligible for GC, the
fact that the underlying handle is a system wide kernel object that should
be kept for the duration of the program is not the JIT business.
To prevent premature collection of the Mutex you could wrap your code in a
using block (yes, Mutex derives from a Disposable), this is more elegant
than using a static.

using(System.Threading.Mutex m = new System.Threading.Mutex(true,
"YourNameHere"))
{
// Your code here
} // Done with the Mutex, the handle can be released

Willy.
 
P

PL

Thank you, the using block worked fine as well and is as you say more
elegant.

I guess what confuses me here is the definition of "not referenced", if I
have a local
variable in Main that do not change you would think it stays referenced
during the
whole lifetime of the program but apparently not.

I guess I need to read up on the garbage collector.

Considering all the examples I found on the net on how to do this that
didn't use a static variable,
a using block or gc.keepalive it seems to me like only more memory intensive
programs experience
this issue which makes it somewhat dangerous.

PL.
 
W

Willy Denoyette [MVP]

PL said:
Thank you, the using block worked fine as well and is as you say more
elegant.

I guess what confuses me here is the definition of "not referenced", if I
have a local
variable in Main that do not change you would think it stays referenced
during the
whole lifetime of the program but apparently not.

This is something to watch out for. A local variable holding a reference to
an object in the managed heap, will be set to null by the JIT compiler
(running in non-debug mode) when it's no longer used in the scope of the
method. Now in the case of a Mutex, the underlying OS handle will only be
released when the finalizer comes along, which can be a long time after the
reference was null'ed. To take control of the lifetime of such an unmanaged
resource you should adopt the disposing pattern and wrap your code in a
using block, just like I've done with the using block.

Willy.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top