Charles,
Perhaps OO is the wrong expression, but I am referring to the concept of
encapsulation.
I'm not so sure I would say that Deterministic Finalization is encapsulation
per se, although I follow your train of thought. In that the class itself
"knows" when it should be cleaned up, ergo the Finalize method. However
Deterministic refers to WHEN the class is allowed to clean up, not so much
that it does know how to or not ;-) However that is not really what the
problem here is, so we don't need to expend time on a largely academic
debate!
When the reference count of the serial port class goes to zero (the object
reference goes out of scope) the port must be closed immediately. Otherwise,
if the user tries to open the port for another session it will fail because
the port is still open from the previous session.
There are NO reference counts in VB.NET! the GC does not use Reference
Counts it actually checks all variables to see if one of them currently
reference the object. For a reasonable complete explanation of how this
works see:
http://msdn.microsoft.com/msdnmag/issues/1100/gci/
http://msdn.microsoft.com/msdnmag/issues/1200/GCI2/
Largely because there is no reference counts, VB.NET cannot know when to
clean up an object! The GC itself needs to do it, at its leisure.
I suppose what I want is a method on the serial class that I can guarantee
will be called when the object reference goes out of scope. Then I can
recover in the event that the caller does not call Dispose.
As I've tried to state There is no method! Or more appropriately the
Finalize/Dispose pattern is the method! ;-)
As far as closing the application goes, the user clicks the Close button,
top right. In this case, because Finalize is not called, the serial class
keeps the application and debugger alive. This is because it starts a second
thread to read characters from the port asynchronously, which never gets
shut down.
Ah! there's the rub!!! ;-)
Does this second thread reference your serial class also? I would expect
that it needs to reference your serial class as its reading from it, hence
there is a "live" reference to your object, ergo the GC cannot collect it.
If the GC cannot collect it, then the Finalize method cannot be called!
You need to "notify" the second thread that it is time to finish, the
"preferred" method is to use an AutoResetEvent or ManualResetEvent or other
"flag" that the main thread can set that the background thread can check. I
normally embed the serialport, ResetEvent, and Thread in a class of its own
that has methods that each thread uses to "communicate" with the other
thread.
Alternatively when you create the Background Thread, do you set the
Thread.IsBackground property, so that it knows it should be aborted when the
main thread exists?
A third alternative, would be to handle the Application.ThreadExit or
Application.AppliationExit in your serial class so it knows when your "main
thread" exited, allowing it to "give up"
I'm sure there are a couple of other possibilities ;-)
Hope this helps
Jay
Charles Law said:
Hi Jay
Perhaps OO is the wrong expression, but I am referring to the concept of
encapsulation. To require Dispose to be called by the user of a service
implies that they know something about the internal operation of the
service, i.e. that it has unmanaged resources that need to be released.
Although you say that if they don't call Dispose the Finalize method will
take care of it, it is also the case that you cannot guarantee when the
Finalize method will be called (if at all, in the case of exiting the
program).
The situation I have is a main form that creates a class. This class opens a
serial port. It may open a second serial port, and may also open one and
close another.
When the reference count of the serial port class goes to zero (the object
reference goes out of scope) the port must be closed immediately. Otherwise,
if the user tries to open the port for another session it will fail because
the port is still open from the previous session.
I have read the articles you pointed to, but they basically confirm the
non-deterministic nature of the Finalize method.
I can see how the Dispose method allows the developer to force an object to
free its handles etc. but failure to do so would cause the serial class to
misbehave, which I want to avoid (as an implementor of the serial class).
I hope that all makes sense.
I suppose what I want is a method on the serial class that I can guarantee
will be called when the object reference goes out of scope. Then I can
recover in the event that the caller does not call Dispose.
As far as closing the application goes, the user clicks the Close button,
top right. In this case, because Finalize is not called, the serial class
keeps the application and debugger alive. This is because it starts a second
thread to read characters from the port asynchronously, which never gets
shut down.
Is there anything I can do about this, as the implementor of the serial
class?
Charles
<<snip>>