![](/img/trans.png)
[英]Will an object be disposed automatically after an asynchronous event it subscribed to is raised?
[英]Why isn't ThreadAbortException automatically rethrown if raised after an asynchronous await?
在调查finally
, await
和ThreadAbortException的问题时 ,我又来了一个怪癖。 根据文件 :
ThreadAbortException是一个可以捕获的特殊异常,但它会在catch块的末尾自动再次引发。
但请考虑这个控制台程序:
class Program
{
static void Main()
{
Run(false).GetAwaiter().GetResult();
Run(true).GetAwaiter().GetResult();
}
static async Task Run(bool yield)
{
Console.WriteLine(yield ? "With yielding" : "Without yielding");
try
{
try { await Abort(yield); }
catch (ThreadAbortException)
{
Console.WriteLine(" ThreadAbortException caught");
} // <-- ThreadAbortException should be automatically rethrown here
}
catch (ThreadAbortException)
{
Console.WriteLine(" Rethrown ThreadAbortException caught");
Thread.ResetAbort();
}
}
static async Task Abort(bool yield)
{
if (yield)
await Task.Yield();
Thread.CurrentThread.Abort();
}
}
当我在Visual Studio 2015中编译它时,输出是:
Without yielding
ThreadAbortException caught
Rethrown ThreadAbortException caught
With yielding
ThreadAbortException caught
所以在Task.Yield()
之后Task.Yield()
的ThreadAbortException不再被catch
块自动重新Task.Yield()
! 为什么是这样?
如果您不await Task.Yield
,它发生的原因是代码在与调用者相同的线程上同步执行,所以它就像根本不是async
。
当您await
,延续将在ThreadPool
线程上排队,该线程是一个托管线程,行为不同。
由于内部被捕获并从与当前不同的线程重新抛出,因此它不会保留它在移位逻辑中的“ 特殊应用程序查杀 ”异常的性质。
另外,如果是重新抛出它,你甚至不能使用Thread.ResetAbort()
因为它在当前线程上工作,并且不会对实际中止的线程起作用。
MSDN文档也解释了这一点 :
如果在公共语言运行库创建的线程中未处理任何这些异常,则异常将终止该线程,但公共语言运行库不允许该异常继续进行。
如果在主线程或从非托管代码进入运行时的线程中未处理这些异常,则它们会正常进行,从而导致应用程序终止。
我对这背后的基本原理的猜测是:重新抛出ThreadAbortException
以避免顽固的线程在它们不应该尝试并保持活着时,但让它流动并杀死其他不同的线程可能是一个非常糟糕的主意并导致意外的行为。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.