后台线程的预期 ThreadAbort

gal*_*13x 5 .net c# multithreading

我有以下内容。

public static Thread testThread = new Thread(ThreadStart) {Name = "TestThread", IsBackground = true};
private void Form_Load()
{
    testThread.Start()
}
private static void ThreadStart()
{
    int count = 0;
    try
    {
        while (true)
        {
            count++;
        }
    }
    catch (Exception ex)
    {

        StreamWriter stream = new StreamWriter(File.OpenWrite("Exception.txt"));
        stream.WriteLine(count + "\n" + ex);
        stream.Flush();
        stream.Close();
    }
}
Run Code Online (Sandbox Code Playgroud)

当我打电话时,Thread.Abort()我捕捉到异常并写出到文件中。但是,如果我改为关闭应用程序,则不会写入任何内容。我也有

AppDomain.CurrentDomain.UnhandledException +=
   new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);
Application.ThreadException +=
   new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
Run Code Online (Sandbox Code Playgroud)

但它似乎从未抛出异常。

我想添加一个问题是谨慎的。

当父进程退出时,正在运行的后台线程会发生什么?我的理解是抛出 ThreadAbortException 以退出线程。如果是这种情况,如何捕获 ThreadAbortException 以清理线程中可能存在的资源?

Alo*_*aus 5

当 CLR 关闭进程时,它不会调用 Thread.Abort 或类似的方法。你的线程方法不会像你的 main 方法那样退出。

  1. 当您离开 main 方法或调用 Environment.Exit 时,它所做的第一件事是在超时(.NET 2.0 中为 2 秒)的情况下终结所有对象,然后无论当前挂起的终结器如何,它将继续终止应用程序。
  2. 接下来调用关键终结器。
  3. 然后,所有线程都将挂起,以便在 CLR 关闭时它们不会造成损害。
  4. 您的应用程序已退出。


Chr*_*ain 4

首先,应用程序可能没有退出,因为您没有将它们放入后台线程。我的猜测是任务管理器将显示意外运行的 EXE 副本。在调用 Start 之前,您需要在线程对象上将 Thread.IsBackground 设置为 true。

其次,文档明确揭穿了您期望的行为:

笔记

当公共语言运行时 (CLR) 停止后台线程时,在托管可执行文件中的所有前台线程都结束后,它 不会使用 System.Threading.Thread.Abort。因此,您无法使用 ThreadAbortException 来检测 CLR 何时终止后台线程。

编辑:

当进程退出时,无需清理工作线程持有的资源,因为您知道,进程正在退出。关于后台线程的约定是,当进程退出时,它们可以随时被终止。因此,如果您的后台线程正在执行需要事务正确性的操作,那么它们可能不应该是后台线程。让它们成为前台线程,并让它们定期检查或等待重置事件,以查看它们是否应该退出并允许进程结束。

  • 在这种情况下,请参阅我上面提到的文档。MSDN 在 100000 次中赢得了 99999 次关于堆栈溢出的某人的意见。 (2认同)