c# - 析构函数永远不会被调用

标签 c# multithreading

<分区>

我有一个类 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.
    }
  }
}

关于c# - 析构函数永远不会被调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18490123/

相关文章:

multithreading - JDK 中的异步 NIO 是如何工作的?

c# - 如何解决 LINQ to Entities 无法识别方法 'System.String ToString()' 方法?

c# - VS 2019中如何在非grpc服务项目中添加proto文件

javascript - 给定文化的文化特定货币

java - 将值从辅助线程传递到主线程

java - 如何比较线程对象

c# - 在控制台应用程序中屏蔽密码参数

c# - Ninject: Controller 的实体上下文

Java并行同步2个线程

java - 通过为单个线程分配唯一的 ID 来提高输出的清晰度