析构函数永远不会被调用

Edg*_*tat 15 c# multithreading

我有一个类Class,Thread它在它的构造函数中创建.该线程运行一个while(true)循环,从a读取非关键数据NetStream.线程将被析构函数中止:

~Class()
{
 _thread.Abort();
 _thread = null;
}
Run Code Online (Sandbox Code Playgroud)

当程序想要结束对Class实例 的使用时ClassInstance,它会调用:

ClassInstance = null;
GC.Collect;
Run Code Online (Sandbox Code Playgroud)

我认为这意味着那时候~Class()会自动调用 - 但事实并非如此.

该线程即使在Application.Exit()返回之后也会继续运行Main().

Bri*_*eon 8

代码的关键部分不包括在内; 线程如何启动以及它运行的方法.如果我不得不猜测,我会说你很可能通过传递一个实例方法来启动线程Class.所以基本上你的类实例仍然以线程的运行为根.您尝试在终结器中停止线程,但终结器将永远不会运行,因为实例仍然是root,导致catch-22情况.

此外,您提到该线程正在运行非关键代码,这是您使用的理由Thread.Abort.这真的不是一个足够好的理由.很难控制ThreadAbortException注入线程的位置,因此可能会破坏您没有预料到的关键程序数据结构.

使用TPL附带的新合作取消机制.更改while (true)循环以轮询CancellationToken.Dispose实施时在方法中发出取消信号IDisposable.不要包含终结器(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.
    }
  }
}
Run Code Online (Sandbox Code Playgroud)


Rah*_*thi 6

如果你实现IDisposable并处置了对象,那么Dispose中的代码将会运行,但是不能保证也会调用析构函数.

垃圾收集器形成了一种浪费时间的观点.因此,如果您想要一个可预测的配置,您可以使用IDisposable.

检查这个帖子