C#线程中止异常

4

thread.Abort()之后会发生什么?

假设我有以下代码:

Thread mWorker = new Thread(new ThreadStart(this.run));
..
mWorker.Start();

**where**

private void run() 
{
      Logger.d(TAG, "run()");

      ...
      try {
        while (this.mRunning){
          ...
        }
      } catch (ThreadAbortException tae){
           Logger.e(TAG,"some msg", tae);
           this.doSomething();
      } catch (IOException ioe){
           Logger.e(TAG,"some msg", ioe);
           this.doSomething();
      } catch (Exception e){
           Logger.e(TAG,"some msg", e);
           this.doSomething();
      } finally {
            gracefoulyClose();
      }

      Logger.d(TAG, "run() - ended");
}

线程更为复杂,但本质在此展示。那么当Abort()被调用时会发生什么?我的catch会起作用并继续调用doSomething()吗?

因为我仍然能在控制台中看到:

A first chance exception of type 'System.Threading.ThreadAbortException' occurred in mscorlib.dll
An exception of type 'System.Threading.ThreadAbortException' occurred in mscorlib.dll but was not handled in user code

但是我为此有一个条件。对吧?

3个回答

7

根据文档

当调用Abort方法来销毁线程时,公共语言运行时会抛出ThreadAbortException异常。ThreadAbortException是一个特殊的异常,可以被捕获,但在catch块结束时它会自动再次抛出。当引发此异常时,运行时会执行所有finally块以结束线程。因为线程可能在finally块中执行无限计算或调用Thread.ResetAbort取消中止,所以无法保证线程将结束。如果你想等待中止的线程结束,可以调用Thread.Join方法。Join是一个阻塞调用,在线程实际停止执行之前不会返回。

换句话说,在捕获ThreadAbortException的catch块之后,该异常会被重新引发,因此您的最后一个日志记录行(例如Logger.d(TAG, "run() - ended"))将不会执行。但由于对this.doSoemthing的调用位于ThreadAbortException的catch块中,因此它执行。

请注意,您的finally确实会执行(请参考上面的文档)。


我的try catch没问题吧?因为当你使用"try {code A} catch (Ex e){}"时,你知道代码A可能会抛出异常,但是我的代码不会抛出线程Abort...不知道我说的是否有意义?我的代码会捕获AbortExcetion吗? - pulancheck1988
如果在 while 循环中发生了 ThreadAbortException,那么是的,它将被捕获在 catch 块中。ThreadAbortException 是一种特殊的异常,可能由 .Net 运行时抛出,而不一定是由您的代码引起的。 - dcp

1
如果你在代码中使用了 response.redirect();,那么它会内部运行 thread.abort();,因此会引发异常。相反,你可以使用 Response.Redirect(url,false);

当我使用Response.End();时,我遇到了“线程中止异常”,但如果我使用HttpContext.Current.ApplicationInstance.CompleteRequest();代替,我就不会遇到这个异常,但是会出现一个新的异常:“服务器无法在HTTP标头发送后附加标头”,你有什么建议吗? - Binny

0
你遇到了ThreadAbortException异常,因为在线程运行完成之前,上下文已经退出。你需要等待线程完成后再退出。如果你想要退出,你需要确保你的线程能够接收一个信号(并且对其进行操作),表明你的程序希望结束,然后管理程序执行的代码必须等待线程完成:
if (mThread != null && mThread.IsAlive) {
    mThread.Join();
}

如果您担心线程永远不会退出,请使用超时重载,并在计时器触发时显式终止线程。


你在一行中检查 mThread != null && mThread.IsAlive。如果 mThread 为 null,这可能会导致访问冲突。 - Hao Nguyen
只要空值检查是条件语句中的第一项,就不会抛出错误。这仅仅是一个例子,并不能适用于所有软件情况。请不要过于追求细节,更多地关注问题本身。 - Sean H

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接