473,408 Members | 1,747 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,408 software developers and data experts.

Did GC eat my mutex? Why did Mutex need to be static?

I use a mutex to disallow starting a second application instance. This
did not work in a release build until I made it static member of my
MainForm class.

In a debug build, first instance got ownership, second did not and
terminated. In a release build, the second instance *also* got
ownership. I "fixed" it by making the mutex a static member of my
MainForm class.

Did the garbage collector eat my mutex because it is not referenced
again after Application.Run is called?

I could not reproduce this on a new simple WinForm project; I tried
making all the project setting the same. Here's the code that did not
work in release build.

[STAThread]
static void Main()
{
try
{
bool firstInstance = false;
string safeName = Application.UserAppDataPath.Replace(@"\","_");
Mutex mutex = new Mutex(true, safeName, out firstInstance);
if(false == firstInstance)
{
return;
}
Application.Run(new FrmMain());
}
catch(Exception ex)
{
Err.Show(ex, "Caught an unexpected exception in FrmMain");
}
}
Nov 16 '05 #1
16 3118
Ed Sutton <S_*************@nomadics.com> wrote:
Did the garbage collector eat my mutex because it is not referenced
again after Application.Run is called?
Yes - it's quite at liberty to do so.
I could not reproduce this on a new simple WinForm project; I tried
making all the project setting the same. Here's the code that did not
work in release build.

[STAThread]
static void Main()
{
try
{
bool firstInstance = false;
string safeName = Application.UserAppDataPath.Replace(@"\","_");
Mutex mutex = new Mutex(true, safeName, out firstInstance);
if(false == firstInstance)
{
return;
}
Application.Run(new FrmMain());
}
catch(Exception ex)
{
Err.Show(ex, "Caught an unexpected exception in FrmMain");
}
}


Put a GC.KeepAlive(mutex); at the end of your try block, and all should
be well.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #2
I just discovered it works in a release build if I add a mutex.Close()
after Application.Run().

It appears I need to learn about how the GC works.

-Ed
Ed Sutton wrote:
I use a mutex to disallow starting a second application instance. This
did not work in a release build until I made it static member of my
MainForm class.

In a debug build, first instance got ownership, second did not and
terminated. In a release build, the second instance *also* got
ownership. I "fixed" it by making the mutex a static member of my
MainForm class.

Did the garbage collector eat my mutex because it is not referenced
again after Application.Run is called?

I could not reproduce this on a new simple WinForm project; I tried
making all the project setting the same. Here's the code that did not
work in release build.

[STAThread]
static void Main()
{
try
{
bool firstInstance = false;
string safeName = Application.UserAppDataPath.Replace(@"\","_");
Mutex mutex = new Mutex(true, safeName, out firstInstance);
if(false == firstInstance)
{
return;
}
Application.Run(new FrmMain());
}
catch(Exception ex)
{
Err.Show(ex, "Caught an unexpected exception in FrmMain");
}
}

Nov 16 '05 #3
Ed Sutton <S_*************@nomadics.com> wrote:
I just discovered it works in a release build if I add a mutex.Close()
after Application.Run().

It appears I need to learn about how the GC works.


Basically the GC can tell that the mutex variable isn't used again
after it's created, so it's no longer considered "live".

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #4
Hi John,

Thank you very much for your reply.
Basically the GC can tell that the mutex variable isn't used again
after it's created, so it's no longer considered "live".


How you described it sounds very efficient. I guess my C++ experience
was leading me to think it would not be garbage collected until it went
out of scope. In most cases, I believe this type of thinking has not
gotten me into trouble.

However, I am beginning to think I have been lucky. I am concerned
about objects that I share between threads being garbage collected. My
objects that are declared static are ok. But I am starting to be
concerned about other objects that may not be static.

-Ed
Nov 16 '05 #5
Hi,

The garbage collector only collects objects which don't have at least one
valid reference. In your case there seems to be a valid reference because
Application.Run doens't return until the app quits and so mutex is a valid
though local variable.

The "problem" is with the compiler, it is the compiler that can see that you
don't use the created object. So in release build when optimizing, it sees
that mutex isn't used. Therefore there won't even be a local variable
"mutex" in the release build (ilasm). It creates the mutex but it doesn't
store its reference anywhere, which is the reason the gc collects it.

Putting mutex.Close after Application.Run is a good solution to prevent the
unwanted optimalization.
HTH,
greetings
"Ed Sutton" <S_*************@nomadics.com> wrote in message
news:eM*************@TK2MSFTNGP11.phx.gbl...
I use a mutex to disallow starting a second application instance. This
did not work in a release build until I made it static member of my
MainForm class.

In a debug build, first instance got ownership, second did not and
terminated. In a release build, the second instance *also* got
ownership. I "fixed" it by making the mutex a static member of my
MainForm class.

Did the garbage collector eat my mutex because it is not referenced
again after Application.Run is called?

I could not reproduce this on a new simple WinForm project; I tried
making all the project setting the same. Here's the code that did not
work in release build.

[STAThread]
static void Main()
{
try
{
bool firstInstance = false;
string safeName = Application.UserAppDataPath.Replace(@"\","_");
Mutex mutex = new Mutex(true, safeName, out firstInstance);
if(false == firstInstance)
{
return;
}
Application.Run(new FrmMain());
}
catch(Exception ex)
{
Err.Show(ex, "Caught an unexpected exception in FrmMain");
}
}

Nov 16 '05 #6
Ed Sutton <S_*************@nomadics.com> wrote:
Basically the GC can tell that the mutex variable isn't used again
after it's created, so it's no longer considered "live".


How you described it sounds very efficient. I guess my C++ experience
was leading me to think it would not be garbage collected until it went
out of scope. In most cases, I believe this type of thinking has not
gotten me into trouble.

However, I am beginning to think I have been lucky. I am concerned
about objects that I share between threads being garbage collected. My
objects that are declared static are ok. But I am starting to be
concerned about other objects that may not be static.


The only time this is a concern is when an object being garbage
collected (or really, finalized - garbage collection itself is very
unlikely to cause you any problems) causes some side-effect which is
undesirable. Aside from this mutex case (and similar ones, eg "having a
file open for locking"), I don't think it's likely to be a problem for
you.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #7
Ed Sutton wrote:
I use a mutex to disallow starting a second application instance. This
did not work in a release build until I made it static member of my
MainForm class.

In a debug build, first instance got ownership, second did not and
terminated. In a release build, the second instance *also* got
ownership. I "fixed" it by making the mutex a static member of my
MainForm class.

Did the garbage collector eat my mutex because it is not referenced
again after Application.Run is called?

I could not reproduce this on a new simple WinForm project; I tried
making all the project setting the same. Here's the code that did not
work in release build.

[STAThread]
static void Main()
{
try
{
bool firstInstance = false;
string safeName = Application.UserAppDataPath.Replace(@"\","_");
Mutex mutex = new Mutex(true, safeName, out firstInstance);
if(false == firstInstance)
{
return;
}
Application.Run(new FrmMain());
}
catch(Exception ex)
{
Err.Show(ex, "Caught an unexpected exception in FrmMain");
}
}

The correct solution is:

[STAThread]
static void Main()
{
bool firstInstance = false;
string safeName = Application.UserAppDataPath.Replace(@"\","_");
using(Mutex mutex = new Mutex(true, safeName, out firstInstance))
{
if(false == firstInstance)
return;

try
{
Application.Run(new FrmMain());
}
catch(Exception ex)
{
Err.Show(ex, "Caught an unexpected exception in FrmMain");
}
}
}
--
Greetings
Jochen

Do you need a memory-leak finder ?
http://www.codeproject.com/tools/leakfinder.asp
Do you need daily reports from your server ?
http://sourceforge.net/projects/srvreport/
Nov 16 '05 #8
Hmmm, How can the GC collect it when it's reference is not stored somewhere?
Did you actually look at the IL?

Not sure if you aren't confusing compiler with Jitter, but this has nothing
to do with the compiler and compiler optimizations, it's actually the Jitter
that 'sees' that the reference is not longer needed when Application.Run
returns, so it sets the reference to null when calling Application run, so
it's a runtime optimization.
When running in the debugger, the Jitter doesn't perform any kind of
"optimizations', as such the mutex is maintained until main goes out of
scope.

Willy.

"BMermuys" <so*****@someone.com> wrote in message
news:eB**************@TK2MSFTNGP12.phx.gbl...
Hi,

The garbage collector only collects objects which don't have at least one
valid reference. In your case there seems to be a valid reference because
Application.Run doens't return until the app quits and so mutex is a valid
though local variable.

The "problem" is with the compiler, it is the compiler that can see that
you
don't use the created object. So in release build when optimizing, it
sees
that mutex isn't used. Therefore there won't even be a local variable
"mutex" in the release build (ilasm). It creates the mutex but it doesn't
store its reference anywhere, which is the reason the gc collects it.

Putting mutex.Close after Application.Run is a good solution to prevent
the
unwanted optimalization.
HTH,
greetings
"Ed Sutton" <S_*************@nomadics.com> wrote in message
news:eM*************@TK2MSFTNGP11.phx.gbl...
I use a mutex to disallow starting a second application instance. This
did not work in a release build until I made it static member of my
MainForm class.

In a debug build, first instance got ownership, second did not and
terminated. In a release build, the second instance *also* got
ownership. I "fixed" it by making the mutex a static member of my
MainForm class.

Did the garbage collector eat my mutex because it is not referenced
again after Application.Run is called?

I could not reproduce this on a new simple WinForm project; I tried
making all the project setting the same. Here's the code that did not
work in release build.

[STAThread]
static void Main()
{
try
{
bool firstInstance = false;
string safeName = Application.UserAppDataPath.Replace(@"\","_");
Mutex mutex = new Mutex(true, safeName, out firstInstance);
if(false == firstInstance)
{
return;
}
Application.Run(new FrmMain());
}
catch(Exception ex)
{
Err.Show(ex, "Caught an unexpected exception in FrmMain");
}
}


Nov 16 '05 #9
Hi,

"Willy Denoyette [MVP]" <wi*************@pandora.be> wrote in message
news:%2****************@TK2MSFTNGP12.phx.gbl...
Hmmm, How can the GC collect it when it's reference is not stored somewhere?

Maybe because there is a *managed heap* which keeps track of all created
objects. The GC checks each object on the managed heap to see if it has any
valid references, if there aren't it cleans up the object.
Did you actually look at the IL?

Not sure if you aren't confusing compiler with Jitter, but this has nothing to do with the compiler and compiler optimizations, it's actually the Jitter that 'sees' that the reference is not longer needed when Application.Run
returns, so it sets the reference to null when calling Application run, so
it's a runtime optimization.
When running in the debugger, the Jitter doesn't perform any kind of
"optimizations', as such the mutex is maintained until main goes out of
scope.
I wouldn't answer such a question before looking at the ILASM. I wonder if
you looked ? And yes I mean the compiler and not the jitter and do know the
difference.

If you look at release ilasm you will see that the reference from the
created mutex isn't stored anywhere, there isn't even a local variable
'mutex' . This is a compiler optimalization that happens only in release
build.
Greetings


Willy.

"BMermuys" <so*****@someone.com> wrote in message
news:eB**************@TK2MSFTNGP12.phx.gbl...
Hi,

The garbage collector only collects objects which don't have at least one valid reference. In your case there seems to be a valid reference because Application.Run doens't return until the app quits and so mutex is a valid though local variable.

The "problem" is with the compiler, it is the compiler that can see that
you
don't use the created object. So in release build when optimizing, it
sees
that mutex isn't used. Therefore there won't even be a local variable
"mutex" in the release build (ilasm). It creates the mutex but it doesn't store its reference anywhere, which is the reason the gc collects it.

Putting mutex.Close after Application.Run is a good solution to prevent
the
unwanted optimalization.
HTH,
greetings
"Ed Sutton" <S_*************@nomadics.com> wrote in message
news:eM*************@TK2MSFTNGP11.phx.gbl...
I use a mutex to disallow starting a second application instance. This
did not work in a release build until I made it static member of my
MainForm class.

In a debug build, first instance got ownership, second did not and
terminated. In a release build, the second instance *also* got
ownership. I "fixed" it by making the mutex a static member of my
MainForm class.

Did the garbage collector eat my mutex because it is not referenced
again after Application.Run is called?

I could not reproduce this on a new simple WinForm project; I tried
making all the project setting the same. Here's the code that did not
work in release build.

[STAThread]
static void Main()
{
try
{
bool firstInstance = false;
string safeName = Application.UserAppDataPath.Replace(@"\","_");
Mutex mutex = new Mutex(true, safeName, out firstInstance);
if(false == firstInstance)
{
return;
}
Application.Run(new FrmMain());
}
catch(Exception ex)
{
Err.Show(ex, "Caught an unexpected exception in FrmMain");
}
}



Nov 16 '05 #10
Ok, I'm confused but interested in understanding this.

Here's my simplified source with the debug and release IL pasted below.
I can not reproduce the problem in this simplified test case which
leads my non-expert-opinion to believe it is related to the garbage
collector coming alive in the real full-blown application that is
finalizing the mutex. If it was a release build code optimization,
shouldn't I have been able to recreate the behavior in my simplified
test case?

Opinions?

-Ed

Simplified Test Case Source
---------------------------
[STAThread]
static void Main()
{
bool firstInstance = false;
Mutex mutex = new Mutex(true, "MyMutex", out firstInstance);
if(false == firstInstance)
{
return;
}
Application.Run(new Form1());
}

Debug IL
---------
..method private hidebysig static void Main() cil managed
{
.entrypoint
.custom instance void [mscorlib]System.STAThreadAttribute::.ctor() =
( 01 00 00 00 )
// Code size 32 (0x20)
.maxstack 4
.locals init ([0] bool firstInstance,
[1] class [mscorlib]System.Threading.Mutex mutex)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: ldc.i4.1
IL_0003: ldstr "MyMutex"
IL_0008: ldloca.s firstInstance
IL_000a: newobj instance void
[mscorlib]System.Threading.Mutex::.ctor(bool,

string,

bool&)
IL_000f: stloc.1
IL_0010: ldloc.0
IL_0011: brtrue.s IL_0015
IL_0013: br.s IL_001f
IL_0015: newobj instance void TestMutex.Form1::.ctor()
IL_001a: call void
[System.Windows.Forms]System.Windows.Forms.Application::Run(class
[System.Windows.Forms]System.Windows.Forms.Form)
IL_001f: ret
} // end of method Form1::Main

Release (Optimize Code=True)
----------------------------
..method private hidebysig static void Main() cil managed
{
.entrypoint
.custom instance void [mscorlib]System.STAThreadAttribute::.ctor() =
( 01 00 00 00 )
// Code size 31 (0x1f)
.maxstack 4
.locals ([0] bool firstInstance)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: ldc.i4.1
IL_0003: ldstr "MyMutex"
IL_0008: ldloca.s firstInstance
IL_000a: newobj instance void
[mscorlib]System.Threading.Mutex::.ctor(bool,

string,

bool&)
IL_000f: pop
IL_0010: ldloc.0
IL_0011: brtrue.s IL_0014
IL_0013: ret
IL_0014: newobj instance void TestMutex.Form1::.ctor()
IL_0019: call void
[System.Windows.Forms]System.Windows.Forms.Application::Run(class
[System.Windows.Forms]System.Windows.Forms.Form)
IL_001e: ret
} // end of method Form1::Main
Nov 16 '05 #11
Seems we are talking about two different build types.

1) Release build (csc filename.cs )

The return value of the ctor call is stored in a local variable V_2 in
following IL snippet (taken by compiling the sample from this thread using
the command line compiler <csc filename.cs>).

..method private hidebysig static void Main() cil managed
{
.entrypoint
.custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01
00 00 00 )
// Code size 55 (0x37)
.maxstack 4
.locals init (bool V_0,
string V_1,
class [mscorlib]System.Threading.Mutex V_2,
class [mscorlib]System.Exception V_3)
.try
{
....
IL_001b: newobj instance void
[mscorlib]System.Threading.Mutex::.ctor(bool,

string,

bool&)
IL_0020: stloc.2
When building with the /optimize flag the IL will pop the reference returned
from the EE stack, there is no named local variable to store the reference
to the mutex, and you are right, this is a compiler optimization.

IL_001b: newobj instance void
[mscorlib]System.Threading.Mutex::.ctor(bool,

string,

bool&)
IL_0020: pop

But, my point was that even in non optimize build (case 1), the Jitter
can/will optimize away the mutex reference by setting the variable to null,
this is done when first Jitting the method.

Note that this JITter optimization (as all other optimizations) is turned
off when running in a (managed) debugger.

Willy.

"BMermuys" <so*****@someone.com> wrote in message
news:eL*************@TK2MSFTNGP11.phx.gbl...
Hi,

"Willy Denoyette [MVP]" <wi*************@pandora.be> wrote in message
news:%2****************@TK2MSFTNGP12.phx.gbl...
Hmmm, How can the GC collect it when it's reference is not stored

somewhere?

Maybe because there is a *managed heap* which keeps track of all created
objects. The GC checks each object on the managed heap to see if it has
any
valid references, if there aren't it cleans up the object.
Did you actually look at the IL?

Not sure if you aren't confusing compiler with Jitter, but this has

nothing
to do with the compiler and compiler optimizations, it's actually the

Jitter
that 'sees' that the reference is not longer needed when Application.Run
returns, so it sets the reference to null when calling Application run,
so
it's a runtime optimization.
When running in the debugger, the Jitter doesn't perform any kind of
"optimizations', as such the mutex is maintained until main goes out of
scope.


I wouldn't answer such a question before looking at the ILASM. I wonder
if
you looked ? And yes I mean the compiler and not the jitter and do know
the
difference.

If you look at release ilasm you will see that the reference from the
created mutex isn't stored anywhere, there isn't even a local variable
'mutex' . This is a compiler optimalization that happens only in release
build.
Greetings


Willy.

"BMermuys" <so*****@someone.com> wrote in message
news:eB**************@TK2MSFTNGP12.phx.gbl...
> Hi,
>
> The garbage collector only collects objects which don't have at least one > valid reference. In your case there seems to be a valid reference because > Application.Run doens't return until the app quits and so mutex is a valid > though local variable.
>
> The "problem" is with the compiler, it is the compiler that can see
> that
> you
> don't use the created object. So in release build when optimizing, it
> sees
> that mutex isn't used. Therefore there won't even be a local variable
> "mutex" in the release build (ilasm). It creates the mutex but it doesn't > store its reference anywhere, which is the reason the gc collects it.
>
> Putting mutex.Close after Application.Run is a good solution to prevent
> the
> unwanted optimalization.
>
>
> HTH,
> greetings
>
>
> "Ed Sutton" <S_*************@nomadics.com> wrote in message
> news:eM*************@TK2MSFTNGP11.phx.gbl...
>> I use a mutex to disallow starting a second application instance.
>> This
>> did not work in a release build until I made it static member of my
>> MainForm class.
>>
>> In a debug build, first instance got ownership, second did not and
>> terminated. In a release build, the second instance *also* got
>> ownership. I "fixed" it by making the mutex a static member of my
>> MainForm class.
>>
>> Did the garbage collector eat my mutex because it is not referenced
>> again after Application.Run is called?
>>
>> I could not reproduce this on a new simple WinForm project; I tried
>> making all the project setting the same. Here's the code that did not
>> work in release build.
>>
>> [STAThread]
>> static void Main()
>> {
>> try
>> {
>> bool firstInstance = false;
>> string safeName = Application.UserAppDataPath.Replace(@"\","_");
>> Mutex mutex = new Mutex(true, safeName, out firstInstance);
>> if(false == firstInstance)
>> {
>> return;
>> }
>> Application.Run(new FrmMain());
>> }
>> catch(Exception ex)
>> {
>> Err.Show(ex, "Caught an unexpected exception in FrmMain");
>> }
>> }
>
>



Nov 16 '05 #12
Hi,

"Ed Sutton" <S_*************@nomadics.com> wrote in message
news:uj**************@TK2MSFTNGP12.phx.gbl...
Ok, I'm confused but interested in understanding this.

Here's my simplified source with the debug and release IL pasted below.
I can not reproduce the problem in this simplified test case which
leads my non-expert-opinion to believe it is related to the garbage
collector coming alive in the real full-blown application that is
finalizing the mutex. If it was a release build code optimization,
shouldn't I have been able to recreate the behavior in my simplified
test case?
Yes, you did. You can clearly see the difference in debug vs release ilasm.
The release version doesn't have a local variable 'mutex' and so it doesn't
store the reference of the created object.

And if you want to see the behaviour you can add a button which allocates
huge arrays and push it a couple times. In the release version the gc will
kick in and dispose the mutex.

HTH,
greetings


Opinions?

-Ed

Simplified Test Case Source
---------------------------
[STAThread]
static void Main()
{
bool firstInstance = false;
Mutex mutex = new Mutex(true, "MyMutex", out firstInstance);
if(false == firstInstance)
{
return;
}
Application.Run(new Form1());
}

Debug IL
---------
.method private hidebysig static void Main() cil managed
{
.entrypoint
.custom instance void [mscorlib]System.STAThreadAttribute::.ctor() =
( 01 00 00 00 )
// Code size 32 (0x20)
.maxstack 4
.locals init ([0] bool firstInstance,
[1] class [mscorlib]System.Threading.Mutex mutex)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: ldc.i4.1
IL_0003: ldstr "MyMutex"
IL_0008: ldloca.s firstInstance
IL_000a: newobj instance void
[mscorlib]System.Threading.Mutex::.ctor(bool,

string,

bool&)
IL_000f: stloc.1
IL_0010: ldloc.0
IL_0011: brtrue.s IL_0015
IL_0013: br.s IL_001f
IL_0015: newobj instance void TestMutex.Form1::.ctor()
IL_001a: call void
[System.Windows.Forms]System.Windows.Forms.Application::Run(class
[System.Windows.Forms]System.Windows.Forms.Form)
IL_001f: ret
} // end of method Form1::Main

Release (Optimize Code=True)
----------------------------
.method private hidebysig static void Main() cil managed
{
.entrypoint
.custom instance void [mscorlib]System.STAThreadAttribute::.ctor() =
( 01 00 00 00 )
// Code size 31 (0x1f)
.maxstack 4
.locals ([0] bool firstInstance)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: ldc.i4.1
IL_0003: ldstr "MyMutex"
IL_0008: ldloca.s firstInstance
IL_000a: newobj instance void
[mscorlib]System.Threading.Mutex::.ctor(bool,

string,

bool&)
IL_000f: pop
IL_0010: ldloc.0
IL_0011: brtrue.s IL_0014
IL_0013: ret
IL_0014: newobj instance void TestMutex.Form1::.ctor()
IL_0019: call void
[System.Windows.Forms]System.Windows.Forms.Application::Run(class
[System.Windows.Forms]System.Windows.Forms.Form)
IL_001e: ret
} // end of method Form1::Main

Nov 16 '05 #13
Ed,

The underlying OS Mutex object (or mutant), will only be freed when the
finalizer has run on the CLR Mutex object (so Dispose has been called). When
running simple programs this probably didn't happen after the Mutex was
created.
Willy.
"Ed Sutton" <S_*************@nomadics.com> wrote in message
news:uj**************@TK2MSFTNGP12.phx.gbl...
Ok, I'm confused but interested in understanding this.

Here's my simplified source with the debug and release IL pasted below. I
can not reproduce the problem in this simplified test case which leads my
non-expert-opinion to believe it is related to the garbage collector
coming alive in the real full-blown application that is finalizing the
mutex. If it was a release build code optimization, shouldn't I have been
able to recreate the behavior in my simplified test case?

Opinions?

-Ed

Simplified Test Case Source
---------------------------
[STAThread]
static void Main()
{
bool firstInstance = false;
Mutex mutex = new Mutex(true, "MyMutex", out firstInstance);
if(false == firstInstance)
{
return;
}
Application.Run(new Form1());
}

Debug IL
---------
.method private hidebysig static void Main() cil managed
{
.entrypoint
.custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = (
01 00 00 00 )
// Code size 32 (0x20)
.maxstack 4
.locals init ([0] bool firstInstance,
[1] class [mscorlib]System.Threading.Mutex mutex)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: ldc.i4.1
IL_0003: ldstr "MyMutex"
IL_0008: ldloca.s firstInstance
IL_000a: newobj instance void
[mscorlib]System.Threading.Mutex::.ctor(bool,

string,

bool&)
IL_000f: stloc.1
IL_0010: ldloc.0
IL_0011: brtrue.s IL_0015
IL_0013: br.s IL_001f
IL_0015: newobj instance void TestMutex.Form1::.ctor()
IL_001a: call void
[System.Windows.Forms]System.Windows.Forms.Application::Run(class
[System.Windows.Forms]System.Windows.Forms.Form)
IL_001f: ret
} // end of method Form1::Main

Release (Optimize Code=True)
----------------------------
.method private hidebysig static void Main() cil managed
{
.entrypoint
.custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = (
01 00 00 00 )
// Code size 31 (0x1f)
.maxstack 4
.locals ([0] bool firstInstance)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: ldc.i4.1
IL_0003: ldstr "MyMutex"
IL_0008: ldloca.s firstInstance
IL_000a: newobj instance void
[mscorlib]System.Threading.Mutex::.ctor(bool,

string,

bool&)
IL_000f: pop
IL_0010: ldloc.0
IL_0011: brtrue.s IL_0014
IL_0013: ret
IL_0014: newobj instance void TestMutex.Form1::.ctor()
IL_0019: call void
[System.Windows.Forms]System.Windows.Forms.Application::Run(class
[System.Windows.Forms]System.Windows.Forms.Form)
IL_001e: ret
} // end of method Form1::Main

Nov 16 '05 #14
Hi,

"Willy Denoyette [MVP]" <wi*************@pandora.be> wrote in message
news:ut**************@tk2msftngp13.phx.gbl...
Seems we are talking about two different build types.
I assume that the default for a release build is to optimize. (ide default)
But I should have been more clear and explicitly stated that.
<snipped>
But, my point was that even in non optimize build (case 1), the Jitter
can/will optimize away the mutex reference by setting the variable to null, this is done when first Jitting the method.
I think I heard or read about this before. Anyway, it usefull to know that
it's not only the compiler that can do such an optimalization.

Greetings


Note that this JITter optimization (as all other optimizations) is turned
off when running in a (managed) debugger.

Willy.

"BMermuys" <so*****@someone.com> wrote in message
news:eL*************@TK2MSFTNGP11.phx.gbl...
Hi,

"Willy Denoyette [MVP]" <wi*************@pandora.be> wrote in message
news:%2****************@TK2MSFTNGP12.phx.gbl...
Hmmm, How can the GC collect it when it's reference is not stored

somewhere?

Maybe because there is a *managed heap* which keeps track of all created
objects. The GC checks each object on the managed heap to see if it has
any
valid references, if there aren't it cleans up the object.
Did you actually look at the IL?

Not sure if you aren't confusing compiler with Jitter, but this has

nothing
to do with the compiler and compiler optimizations, it's actually the

Jitter
that 'sees' that the reference is not longer needed when Application.Run returns, so it sets the reference to null when calling Application run,
so
it's a runtime optimization.
When running in the debugger, the Jitter doesn't perform any kind of
"optimizations', as such the mutex is maintained until main goes out of
scope.


I wouldn't answer such a question before looking at the ILASM. I wonder
if
you looked ? And yes I mean the compiler and not the jitter and do know
the
difference.

If you look at release ilasm you will see that the reference from the
created mutex isn't stored anywhere, there isn't even a local variable
'mutex' . This is a compiler optimalization that happens only in release build.
Greetings


Willy.

"BMermuys" <so*****@someone.com> wrote in message
news:eB**************@TK2MSFTNGP12.phx.gbl...
> Hi,
>
> The garbage collector only collects objects which don't have at least

one
> valid reference. In your case there seems to be a valid reference

because
> Application.Run doens't return until the app quits and so mutex is a

valid
> though local variable.
>
> The "problem" is with the compiler, it is the compiler that can see
> that
> you
> don't use the created object. So in release build when optimizing, it > sees
> that mutex isn't used. Therefore there won't even be a local variable > "mutex" in the release build (ilasm). It creates the mutex but it

doesn't
> store its reference anywhere, which is the reason the gc collects it.
>
> Putting mutex.Close after Application.Run is a good solution to prevent > the
> unwanted optimalization.
>
>
> HTH,
> greetings
>
>
> "Ed Sutton" <S_*************@nomadics.com> wrote in message
> news:eM*************@TK2MSFTNGP11.phx.gbl...
>> I use a mutex to disallow starting a second application instance.
>> This
>> did not work in a release build until I made it static member of my >> MainForm class.
>>
>> In a debug build, first instance got ownership, second did not and
>> terminated. In a release build, the second instance *also* got
>> ownership. I "fixed" it by making the mutex a static member of my
>> MainForm class.
>>
>> Did the garbage collector eat my mutex because it is not referenced
>> again after Application.Run is called?
>>
>> I could not reproduce this on a new simple WinForm project; I tried
>> making all the project setting the same. Here's the code that did not >> work in release build.
>>
>> [STAThread]
>> static void Main()
>> {
>> try
>> {
>> bool firstInstance = false;
>> string safeName = Application.UserAppDataPath.Replace(@"\","_"); >> Mutex mutex = new Mutex(true, safeName, out firstInstance);
>> if(false == firstInstance)
>> {
>> return;
>> }
>> Application.Run(new FrmMain());
>> }
>> catch(Exception ex)
>> {
>> Err.Show(ex, "Caught an unexpected exception in FrmMain");
>> }
>> }
>
>



Nov 16 '05 #15
BMermuys <so*****@someone.com> wrote:
Yes, you did. You can clearly see the difference in debug vs release ilasm.
The release version doesn't have a local variable 'mutex' and so it doesn't
store the reference of the created object.


That's only part of the problem though. Changing the code so that it
uses the mutex immediately after creating it (e.g. by calling ToString
on it) makes sure that there'll be a local variable - but then the
garbage collector / JIT can still notice that it's not used *after*
that.

Here's an example which demonstrates that behaviour:

using System;

public class NoisyFinalizer
{
~NoisyFinalizer()
{
Console.WriteLine ("Being finalized");
}
}

public class Test
{
static void Main()
{
NoisyFinalizer foo = new NoisyFinalizer();
Console.WriteLine ("Before ToString call");
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine ("GC finished");
Console.WriteLine(foo.ToString());
Console.WriteLine ("After ToString call");
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine ("GC finished");
Console.WriteLine ("Exiting");
}
}

The NoisyFinalizer instance is eligible for garbage collection after
the call to ToString, but before the end of the method.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too
Nov 16 '05 #16
Hi Jon,

"Jon Skeet [C# MVP]" <sk***@pobox.com> wrote in message
news:MP***********************@msnews.microsoft.co m...
BMermuys <so*****@someone.com> wrote:
Yes, you did. You can clearly see the difference in debug vs release ilasm. The release version doesn't have a local variable 'mutex' and so it doesn't store the reference of the created object.
That's only part of the problem though. Changing the code so that it
uses the mutex immediately after creating it (e.g. by calling ToString
on it) makes sure that there'll be a local variable - but then the
garbage collector / JIT can still notice that it's not used *after*
that.


I'm gonna try the code but I have no doubts that you're right.

My answer was directly related to the OP's question in which he didn't use
the object after creation. So I think compiler optimalization was a
good -maybe narrow- answer. Therefore I do appriciate you and Willy to
remind me and the OP of the jitter.

I think it's good to conclude that both the compiler and the jitter can do a
similar kind of optimalization and the gc offcourse cleans up the
reference-less objects.

- The compiler will optimize unused objects when optimizing is turned on
- The jitter will optimize objects which are no longer used (and unused
objects in case the compiler doesn't optimize)

Greetings

Here's an example which demonstrates that behaviour:

using System;

public class NoisyFinalizer
{
~NoisyFinalizer()
{
Console.WriteLine ("Being finalized");
}
}

public class Test
{
static void Main()
{
NoisyFinalizer foo = new NoisyFinalizer();
Console.WriteLine ("Before ToString call");
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine ("GC finished");
Console.WriteLine(foo.ToString());
Console.WriteLine ("After ToString call");
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine ("GC finished");
Console.WriteLine ("Exiting");
}
}

The NoisyFinalizer instance is eligible for garbage collection after
the call to ToString, but before the end of the method.

--
Jon Skeet - <sk***@pobox.com>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too

Nov 16 '05 #17

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: Rocky | last post by:
I am using the following piece of code to ensure that my application only runs once, however I have a few questions about it. static Mutex m_Mutex; << in c# I assume that when the methods are...
4
by: PL | last post by:
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;...
2
by: Martin Maat | last post by:
Hi. I want to use the same mutex in different classes (web pages in an ASP.NET application). In global.asax.cs, the class that starts up first, I create a Mutex like this: static private...
1
by: Kris | last post by:
I want to set a mutex in one windows account and allow another windows account to access this mutex. For testing I have two forms that create a mutex using the C# mutex class. I am logging into...
11
by: Tyler Sample | last post by:
I've been having strange thread conflicts, and after moving the relevant mutex higher and higher I've finally determined that the mutex doesn't seem to be working at all. Here is the relevant...
7
by: Ken Varn | last post by:
I am working in managed C++. I have a Mutex object in which I need to replace the Handle property with a new handle. The new handle is being constructed using Win32 CreateMutex call. I need to...
1
by: cold80 | last post by:
I'm trying to check in my application if another instance of it is already running. I found many code snippets on the net that make use of a named mutex to do this check, but I can't make it work...
3
by: NaeiKinDus | last post by:
Hello, i'm trying to program a thread that would be locked (by a mutex) and that would only be unlocked once that a function (generating data) is done. The purpose is to generate data, and unlock...
2
by: tshad | last post by:
I am running a program as a Windows service which works fine. I am using a Mutex to prevent multiple threads from from accessing my log text file at the same time. It works fine in the Service:...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.