如何检测finally块中的ThreadAbortException? (。净)

时间:2008-12-09 16:02:40

标签: .net multithreading

我在finally块中有一些关键逻辑(带有空的try块),因为我想保证即使线程被中止也会执行代码。但是,我还想检测ThreadAbortException。我发现在try / catch中包装我的关键try / finally块不会捕获ThreadAbortException。有没有办法检测它?

try {
    try { }
    finally {
        // critical logic
    }
} catch(Exception ex) {
    // ThreadAbortException is not caught here, but exceptions thrown
    // from within the critical logic are
}

7 个答案:

答案 0 :(得分:8)

这是一个奇怪的问题。

您发布的代码应该工作。似乎正在进行某种优化,决定不调用你的catch处理程序。

所以,我想用这个来检测异常:

bool threadAborted = true;
try {
  try { }
  finally { /* critical code */ }
  threadAborted = false;
}
finally {
  Console.WriteLine("Thread aborted? {0}", threadAborted);
}
Console.WriteLine("Done");

(我的实际代码只是睡在那个关键的代码部分,所以我可以肯定它会在最终之后中止。)

打印出来:

  

线程已中止?假

嗯,确实很奇怪!

所以我想在那里做更多的工作,欺骗任何“聪明”的优化:

bool threadAborted = true;
try {
  try { }
  finally { /* critical code */ }
  threadAborted = AmIEvil();
}
finally {
  Console.WriteLine("Thread aborted? {0}", threadAborted);
}
Console.WriteLine("Done");

AmIEvil只是:

[MethodImpl(MethodImplOptions.NoInlining)]
static bool AmIEvil() {
  return false;
}

最后打印出来了:

  

线程已中止?真

你有它。在代码中使用它:

try {
  try { }
  finally { /* critical code */ }
  NoOp();
}
catch (Exception ex) {
  // ThreadAbortException is caught here now!
}

NoOp只是:

[MethodImpl(MethodImplOptions.NoInlining)]
static void NoOp() { }

答案 1 :(得分:3)

你可以在catch语句中实际执行ThreadAbortException的代码。问题是一旦执行离开catch块就会重新抛出异常。

如果要实际停止继续异常,可以调用Thread.ResetAbort()。这确实需要完全信任,除非你有一个特定的场景,否则几乎肯定是错误的。

ThreadAbortException

答案 2 :(得分:2)

答案 3 :(得分:2)

我不认为这是可能的。

为什么首先需要处理 ThreadAbortException ?调用 thread.Abort()通常是糟糕设计的标志。有一个标志变量,当设置为true时,只需返回; 来自线程函数,当然要经过适当的清理。

这样你就不必担心异常了。

答案 4 :(得分:2)

如果调用Thread.Abort设计不好,为什么SQL Server会在运行用户代码的线程上调用它?因为这正是查询取消的处理方式,它会导致噩梦。

答案 5 :(得分:0)

我同意arul。 调用Thread.Abort()是糟糕设计的标志。

让我引用MSDN: Thread.Abort的Peter Ritchie(强调是我的):

  

有很多理由不使用Thread.Abort和ThreadAbortException

     

在某些平台(如x64和IA64)上,可以在Monitor.Enter和try块(即使使用lock / SyncLock)之前发生中止,使监视器处于孤立状态。   ThreadAbortException可能发生在第三方代码中,而不是为了处理线程中止而编写的。   在.NET 1.x中处理finally块时,可以中止该线程   使用常规控制流逻辑的异常。   异步异常可以中断对分片状态或资源的修改,使它们损坏。

     

有关详细信息,请参阅:
  http://msmvps.com/blogs/peterritchie/archive/2007/08/22/thead-abort-is-a-sign-of-a-poorly-designed-program.aspx
  http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
  http://blogs.msdn.com/ericlippert/archive/2007/08/17/subtleties-of-c-il-codegen.aspx

答案 6 :(得分:0)

你尝试过这样的事吗?

try {
    try { }
    catch (ThreadAbortException)
    {
      ThreadAbortExceptionBool = true;
    }
    finally {
        // critical logic
        if (ThreadAbortExceptionBool)
          // Whatever
    }
} 
catch(Exception ex) {
    // ThreadAbortException is not caught here, but exceptions thrown
    // from within the critical logic are
}