I have a class Class
that creates a Thread
in it's constructor. This thread runs a while(true)
loop that is reading non-critical data from a NetStream
. The thread will be aborted by the destructor:
~Class()
{
_thread.Abort();
_thread = null;
}
When the program wants to end the use of Class
's instance - ClassInstance
, it calls:
ClassInstance = null;
GC.Collect;
I thought that means that ~Class()
will be caller automatically at that point - but it's not.
This thread keeps running even after Application.Exit()
and returning from Main()
.
There are two reasons that your destructors aren't being called, one is as kishor8dm pointed out that you are using the operator "new" and because of that the "delete" command must be called explicitly.
The constructor code is the construction of t1. Then a copy constructor is used when it is pushed back on the vector. When the clear() is called, it calls the destructor for the object in the vector. Then t1's destructor is called when it goes out of scope.
The destructor will only get called when the garbage collector decides to collect your instance. The garbage collector runs infrequently, typically only when it detects that there is memory pressure. The garbage collector collects ONLY orphaned collections.
Destructors are called when one of the following events occurs: A local (automatic) object with block scope goes out of scope. An object allocated using the new operator is explicitly deallocated using delete . The lifetime of a temporary object ends.
The crucial bit of your code is not included; how the thread is started and what method it is running. If I had to make a guess I would say it is likely you started the thread by passing an instance method of Class
. So basically your class instance is still rooted by the running of the thread. You attempt to stop the thread in the finalizer, but the finalizer will never run because the instance is still rooted leading to a catch-22 situation.
Also, you mentioned that the thread is running non-critical code and that was your justification for using Thread.Abort
. That really is not a good enough reason. It is very hard to control where that ThreadAbortException
will get injected into the thread and as a result it may corrupt critical program data structures you did not anticipate.
Use the new cooperative cancellation mechanisms included with the TPL. Change the while (true)
loop to poll a CancellationToken instead. Signal the cancellation in the Dispose
method when you implement IDisposable
. Do not include a finalizer (destructor in C# terminology). Finalizers are intended to be used to clean up unmanaged resources. Since you have not indicated that unmanaged resources are in play then it is pointless to have a finalizer. You do not have to include a finalizer when implementing IDisposable
. In fact, it is considered bad practice to have one when it is not really needed.
public class Class : IDisposable
{
private Task task;
private CancellationTokenSource cts = new CancellationTokenSource();
Class()
{
task = new Task(Run, cts.Token, TaskCreationOptions.LongRunning);
task.Start();
}
public void Dispose()
{
cts.Cancel();
}
private void Run()
{
while (!cts.Token.IsCancellationRequested)
{
// Your stuff goes here.
}
}
}
If you implement IDisposable
, and dispose the object, then the code in Dispose will run, but there is no guarantee that Destructor will also be called.
Garbage Collector forms an opinion that it is a waste of time. So if you want to have a predictable dispose you can use IDisposable
.
Check this Thread
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With