在Finally块的中间是否可能引发ThreadAbortException?

3
假设以下代码正在单独的线程中运行:
try{
  var stuffToDispose = new SomeClassThatNeedsDisposing();
  //doing thing with stuffToDispose
}
finally{
   if(stuffToDispose != null)
     stuffToDispose.Dispose();
}

使用引发 ThreadAbortException 的机制来终止该线程。在 null 检查和 Dispose() 之间,ThreadAbortException 是否可能发生?即,在 finally 块的中间部分是否会发生异常?

finally{
   if(stuffToDispose != null)
     //This is where the Exception would strike
     stuffToDispose.Dispose();
}

我很确定答案是否定的,但有人坚信它是可能的。

3个回答

4
在.NET Framework中,ThreadAbortExceptioncatchfinally块中都有特殊处理:
  • 如果捕获到ThreadAbortException,它会在catch块结束时自动重新引发(除非通过Thread.ResetAbort抑制)。
  • finally块中,ThreadAbortException直到整个块结束才会被“激活”。这是一种预期的行为。这就是为什么有时候可以在空的try {}块中找到晦涩的代码,而所有内容都在finally部分。这确保了该部分不会被中止。
另一方面,.NET Core 不支持 Thread.Abort(抛出 PlatformNotSupportedException)。为了兼容性,ThreadAbortException 本身并未被移除,因此仍然可以显式地抛出它,但我认为它不再像上述描述那样被处理(我没有测试过)。

哇,这意味着最终可以用来防止某些部分的中止吗?这对我来说是新的,非常有帮助!尽管在.NET 4中它仍然会被中止... - eocron
是的,至少直到 finally 块结束。当然,正如你从例子中看到的那样,这可能会被恶意利用。 - György Kőszeg
除了核心问题之外,这正是我在阅读“无法被吞咽”的保护/重新引发时所想到的工作方式。 - Christopher

2

如果运行在 .NET 4.0.0-4.7.2 下,最终不会被中断

当使用 Thread.Abort() 时,代码将锁定并无限期打印 foo,最终陷入死循环。

class Program
{
    static void Main(string[] args)
    {
        var i = false;
        var t = new Thread(() =>
        {
            try { Console.Write("foo"); } finally { while (true) { i=true; } }
        });
        t.Start();
        Thread.Sleep(200);
        t.Abort();
        t.Join();
        Console.WriteLine("bar = {0}", i);
        Console.ReadKey();
    }
}

然而,不能保证在后续版本中不会执行此操作。

最终将被执行,但如果

.NET 2.0-3.5下运行相同的部分将打印foobar = True,这意味着它被中断了。

但是如果您进行以下修改:

        var t = new Thread(() =>
        {
            try { Console.Write("foo"); } finally { while (true) { Console.Write(".");} }
        });

它将像第一个示例一样无限运行。这很奇怪。

摘要

最好直接向微软询问。


1
根据我的测试,调用Thread.Abort不会中断线程内当前正在运行的finally块。
测试代码:
var thread = new Thread(() =>
{
    try
    {
    }
    catch (ThreadAbortException)
    {
        Console.WriteLine("ThreadAbortException");
        throw;
    }
    finally
    {
        Console.WriteLine("Thread Finally Started");
        Thread.Sleep(200);
        Console.WriteLine("Thread Finally Finished");
    }
})
{ IsBackground = true };
thread.Start();
Thread.Sleep(100);
Console.WriteLine("Aborting...");
thread.Abort();
thread.Join();

输出(.NET Framework 4.8):

线程最终已启动
正在中止...
线程最终已完成

请记住,在 .NET Core 上不支持 Thread.Abort

System.PlatformNotSupportedException:此平台不支持线程中止。


如果你在finally中写入类似*while(true){ i++;}*的代码,并在< .NET 4.0下运行,会发生奇怪的事情,它将被中断。使用你的例子。 - eocron
@eocron 编写 .NET Framework < 4.0 的代码真是令人沮丧。没有 TPL,没有 async/await。Thread.Abort 的行为也不是我的最大问题。 :-) - Theodor Zoulias
是的,但重要的是要提到,淘汰旧答案=)因为我相信它会在4.8中被中断=) - eocron

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