我有一个类 Class
,它在其构造函数中创建了一个 Thread
。此线程运行一个 while(true)
循环,该循环正在从 NetStream
中读取非关键数据。该线程将被析构函数中止:
~Class()
{
_thread.Abort();
_thread = null;
}
当程序想要结束使用Class
的实例——ClassInstance
时,它调用:
ClassInstance = null;
GC.Collect;
我认为这意味着 ~Class()
将在此时自动调用 - 但事实并非如此。
即使在 Application.Exit()
并从 Main()
返回后,该线程仍继续运行。
您的代码的关键部分未包括在内;线程是如何启动的以及它正在运行什么方法。如果我不得不猜测,我会说您很可能通过传递 Class
的实例方法来启动线程。所以基本上你的类实例仍然以线程的运行为基础。您尝试停止终结器中的线程,但终结器永远不会运行,因为该实例仍然是 root 的,从而导致 catch-22 情况。
此外,您提到线程正在运行非关键代码,这是您使用 Thread.Abort
的理由。这真的不是一个足够好的理由。很难控制 ThreadAbortException
将被注入(inject)到线程中的位置,因此它可能会破坏您没有预料到的关键程序数据结构。
使用新的 cooperative cancellation TPL 中包含的机制。更改 while (true)
循环以轮询 CancellationToken反而。当您实现 IDisposable
时,在 Dispose
方法中发出取消信号。不要包含终结器(C# 术语中的析构函数)。终结器旨在用于清理非托管资源。由于您没有指出非托管资源正在发挥作用,因此拥有终结器毫无意义。实现 IDisposable
时不必包含终结器。事实上,在并非真正需要时拥有一个被认为是不好的做法。
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.
}
}
}