IDisposable.Dispose, Object.Finalize and threads

  • Thread starter Francois PIETTE
  • Start date
F

Francois PIETTE

IDisposable.Dispose is documented as the method where you have to release
unmanaged resources.
Dispose is called by Finalize.
Finalize is called by garbage collector after the object becomes
inaccessible.
The documentation says: "The thread on which the finalizer is run is
unspecified".

So the question is: My object has allocated a [win32] window handle using
CreateWindow (called using P/Invoke) and has to destroy it. But Win32 SDK
say that DestroyWindow has to be called from the same thread that called
CreateWindow. This seems impossible given Dispose/Finalize/GC patern.

Any advice ?

btw: Let me know if I should post to another group.
 
D

David Browne

Francois PIETTE said:
IDisposable.Dispose is documented as the method where you have to release
unmanaged resources.
Dispose is called by Finalize.
Finalize is called by garbage collector after the object becomes
inaccessible.
The documentation says: "The thread on which the finalizer is run is
unspecified".

So the question is: My object has allocated a [win32] window handle using
CreateWindow (called using P/Invoke) and has to destroy it. But Win32 SDK
say that DestroyWindow has to be called from the same thread that called
CreateWindow. This seems impossible given Dispose/Finalize/GC patern.

Therefore you should implement IDisposable, but omit the finalizer. Client
code should be clearly warned that failure to call IDisposable.Dispose will
leak a winow handle.

David
 
C

Chad Z. Hower aka Kudzu

David Browne said:
Therefore you should implement IDisposable, but omit the finalizer. Client
code should be clearly warned that failure to call IDisposable.Dispose will
leak a winow handle.

Thats not a very good solution. Thats asking for trouble and in fact violates
the .NET guidelines in general.

I dont see any clean solutions either. Maybe a suspended thread for creating
and destroying - but that wont work either because the finalizer is not
allowed to make external calls.

Francois since I know you are a Borland user you might see what VCL.NET did
regarding this.
 
D

Daniel Billingsley

But the Finalizer is not "supposed" to be called under normal circumstances.
It is a sign that the Dispose() was not properly called, as Dispose() should
call SuppressFinalize.

Look in the help for a section called "Implementing a Dispose Method". In
addition to explaining all this, it gives code for the recommended pattern.

There's a growing school of thought that goes so far to say the Finalizer
should even raise an Exception to make it clear there is a bug (the
Dispose() not being called). Your scenario seems like a good reason to do
that if the memory leak is a big issue.
 
F

Francois Piette

Francois since I know you are a Borland user you might see
what VCL.NET did regarding this.

There are no problem with VCL.NET because in this context the destructor is
always explicitely called. The problem is with native .NET components when
they are used from languages likes C# where object destructors are only
called by the garbage collector.
 
C

Chad Z. Hower aka Kudzu

Daniel Billingsley said:
But the Finalizer is not "supposed" to be called under normal
circumstances. It is a sign that the Dispose() was not properly called,
as Dispose() should call SuppressFinalize.

Thats not correct.

Dispose and Finalize are not the same and in many cases you need both. ONLY
in cases that the Dispose releases the resources that Finalize does should
you call SupressFinalize. This is not the case in most instances.

A file access might be an exmaple that this is. In the Dispose you free the
file handle, but in the Finalize you do it in case the user did not call
Dispose.
There's a growing school of thought that goes so far to say the
Finalizer should even raise an Exception to make it clear there is a bug
(the Dispose() not being called). Your scenario seems like a good
reason to do that if the memory leak is a big issue.

Its problematic if the finalizer throws an exception. The GC generally just
ignores it and goes on. So who will see the exception?



--
Chad Z. Hower (a.k.a. Kudzu) - http://www.hower.org/Kudzu/
"Programming is an art form that fights back"

Get your ASP.NET in gear with IntraWeb!
http://www.atozed.com/IntraWeb/
 
C

Chad Z. Hower aka Kudzu

Francois Piette said:
There are no problem with VCL.NET because in this context the destructor
always explicitely called. The problem is with native .NET components

Thats not correct Francois. I know you and I are at odds a lot - but I am
giving two sessions on this at CTTM (SDC) so I know this area very very well
after weeks of research and experimentation. :)

BTW I forgot to tell you I was in Belgium again two weeks ago. But I'll be at
SDC next week. Would love if you can make it over an meet us just for even
lunch or something.

Ok back to tech.. In Delphi for .NET the destructors are NOT guaranteed to be
called. Destructors in Delphi are implemented as Dispose and are treated thus
the same. So unless the user calls Dispose (or Free or Destroy) from Delphi,
it will NOT be called.
they are used from languages likes C# where object destructors are only
called by the garbage collector.

Well kind of... C# destructors yes because they are implemented as a
finalizer. But a Delphi destructor is implemented as Dispose.....



--
Chad Z. Hower (a.k.a. Kudzu) - http://www.hower.org/Kudzu/
"Programming is an art form that fights back"

Make your ASP.NET applications run faster
http://www.atozed.com/IntraWeb/
 
J

Jon Skeet [C# MVP]

Chad Z. Hower aka Kudzu said:
Thats not correct.

Dispose and Finalize are not the same and in many cases you need both. ONLY
in cases that the Dispose releases the resources that Finalize does should
you call SupressFinalize. This is not the case in most instances.

I disagree - in every case I can think of which I've come across,
Dispose releases the resources that the finalizer would other do.

Why would you *want* to wait until the object is finalized before
releasing resources if you've been explicitly told that the object will
no longer be used?
A file access might be an exmaple that this is. In the Dispose you free the
file handle, but in the Finalize you do it in case the user did not call
Dispose.

So what's an example of it *not* being the case?
 
C

Chad Z. Hower aka Kudzu

Jon Skeet said:
I disagree - in every case I can think of which I've come across,
Dispose releases the resources that the finalizer would other do.

It depends on how the resources are used and if the Dispose is a "Close" or
not. But I guess in most cases it would be the same - but not all.
Why would you *want* to wait until the object is finalized before
releasing resources if you've been explicitly told that the object will
no longer be used?

In some cases the Dispose is more of a "Close" and shares code. But I guess
that if it left resources too - that wouldnt be a commonly needed situation.



--
Chad Z. Hower (a.k.a. Kudzu) - http://www.hower.org/Kudzu/
"Programming is an art form that fights back"

Develop ASP.NET applications easier and in less time:
http://www.atozed.com/IntraWeb/
 
J

Jon Skeet [C# MVP]

Chad Z. Hower aka Kudzu said:
It depends on how the resources are used and if the Dispose is a "Close" or
not. But I guess in most cases it would be the same - but not all.

Possibly not all, although I'd be interested to hear of an example.
Have you heard of any?
In some cases the Dispose is more of a "Close" and shares code. But I guess
that if it left resources too - that wouldnt be a commonly needed situation.

Indeed - and the fact that I can't think of a single situation where
it's the case is fairly telling, I think.

Certainly I believe that your statement that "This is not the case in
most instances" (with regard to Dispose calling SuppressFinalize) in
untrue. (The docs for Dispose even state: "However, once the Dispose
method has been called, it is typically unnecessary for the garbage
collector to call the disposed object's finalizer.")
 
J

JD

The dataview is the only class that I have seen that "kind of" does the
close/dispose pattern. It inherits the MarshalByValueComponent that does
have a finalize method and implements the IDisposable interface. But if you
look in the dataview's constructor it calls GC.SuppressFinalize since it
doesn't have any unmanaged resources, so there is no need to override the
dispose method. But it does override the dispose method which calls the
close method which does some unregistering of events from the datatable.

Actually if you look at the dataview, it implements an interesting pattern
with the datatable in question, its member dvListener (type of
dataviewlistener), the dataview itself, and weak references. I haven't been
able to study the whole pattern but it looks like even if the dataview's
dispose/close method isn't called, the dataview will still be GC'd because
the dvlistener actually registers to the datatables events and the
dvlistener has a weak reference back to the dataview to communicate the
events. Like I said I haven't looked at the whole pattern but it looks like
the dvListener will still be around registered to the datatable's events and
would still hang around but the dataview will be GC'd.
 
J

Jon Skeet [C# MVP]

JD said:
The dataview is the only class that I have seen that "kind of" does the
close/dispose pattern. It inherits the MarshalByValueComponent that does
have a finalize method and implements the IDisposable interface. But if you
look in the dataview's constructor it calls GC.SuppressFinalize since it
doesn't have any unmanaged resources, so there is no need to override the
dispose method. But it does override the dispose method which calls the
close method which does some unregistering of events from the datatable.

I don't see how that is quite what we were talking about. We were
talking about classes which implement IDisposable but which are still
finalized even is Dispose is called. The fact that SuppressFinalize is
called in the constructor instead of in Dispose is relatively
unimportant in this context - interesting though it certainly is.
 
J

JD

I disagree - in every case I can think of which I've come across,
Possibly not all, although I'd be interested to hear of an example.
Have you heard of any?

I thought it may be relevant in the thread of conversation above. The
dataview dispose method does not release resources that the finalizer does.
In this case the finalizer is taken out of the picture right at the
construction of the object, dispose is merely a managed resource cleanup.
Sorry if 'm mistaken.
 
D

Daniel Billingsley

Thats not correct.

Well, it is according to Microsoft's .NET Framework Developer's Guide topic
"Implementing a Dispose Method" available in Visual Studio Help:
"A Dispose method should call the GC.SuppressFinalize method for the object
it is disposing. If the object is currently on the finalization queue,
GC.SuppressFinalize prevents its Finalize method from being called. Remember
that executing a Finalize method is costly to performance. If your Dispose
method has already done the work to clean up the object, then it is not
necessary for the garbage collector to call the object's Finalize method."

In regards to the example code for the Dispose/Finalize pattern given:
"The Finalize method calls the Dispose method that takes parameters, passing
false. You should not re-create Dispose clean-up code within the Finalize
method"

Did that author not have any idea what he was talking about? It's not the
only place I've seen this pattern, BTW.
Dispose and Finalize are not the same and in many cases you need both.
Of course. When did I suggest otherwise? In fact, I'd say you always
should include both, but ideally the Finalizer should never be needed.
the Dispose you free the
file handle, but in the Finalize you do it in case the user did not call
Dispose.
Sounds pretty much like what I wrote, except I pointed out that these days
it is becoming pretty mainstream to consider the client not calling Dispose
as being a "bug", not just something oh well we'll clean up for him.
 
J

Jon Skeet [C# MVP]

Daniel Billingsley said:
Of course. When did I suggest otherwise? In fact, I'd say you always
should include both, but ideally the Finalizer should never be needed.

You shouldn't always include both. If the class only deals with managed
resources (which may themselves contain unmanaged resources) you only
need a Dispose method.

StreamReader/StreamWriter is a good example of that - it includes a
Dispose method which calls Dispose on the underlying stream, but
there's no need to include a finalizer in it, as the stream itself will
have one if it needs it.
 
D

David Browne

Jon Skeet said:
You shouldn't always include both. If the class only deals with managed
resources (which may themselves contain unmanaged resources) you only
need a Dispose method.

StreamReader/StreamWriter is a good example of that - it includes a
Dispose method which calls Dispose on the underlying stream, but
there's no need to include a finalizer in it, as the stream itself will
have one if it needs it.

Also with purely managed resources, Dispose should sometimes be used to
prune dead objects from longer-lived objectcs which reference them.

For instance event consumers should unregister thier event handlers in
Dispose, making them elegible for GC sooner, but should not have a finalizer
because by the time the finalizer runs the whole tree has become
unreachable.

David
 
C

Chad Z. Hower aka Kudzu

Jon Skeet said:
Possibly not all, although I'd be interested to hear of an example.
Have you heard of any?

I ran across some in preparing my sessions. I dont have them right now and I
have to leave tommorrow for the conference. They arent "most" as I stated
incorrectly before, but they do exist.
Certainly I believe that your statement that "This is not the case in
most instances" (with regard to Dispose calling SuppressFinalize) in
untrue. (The docs for Dispose even state: "However, once the Dispose

Yes, the most was not a correct statement.



--
Chad Z. Hower (a.k.a. Kudzu) - http://www.hower.org/Kudzu/
"Programming is an art form that fights back"

Get your ASP.NET in gear with IntraWeb!
http://www.atozed.com/IntraWeb/
 

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