![](/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.