While investigating an issue with finally
, await
, and ThreadAbortException , I came another quirk. According to the documentation :
ThreadAbortException is a special exception that can be caught, but it will automatically be raised again at the end of the catch block.
But consider this console program:
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();
}
}
When I compile this in Visual Studio 2015, the output is:
Without yielding
ThreadAbortException caught
Rethrown ThreadAbortException caught
With yielding
ThreadAbortException caught
So a ThreadAbortException raised after Task.Yield()
is no longer automatically rethrown by a catch
block! Why is this?
The reason why it happens if you don't await Task.Yield
is that the code is executed synchronously on the same thread as the caller so it's like not being async
at all.
When you await
, the continuation will be queued on a ThreadPool
thread which is a managed thread and behaves differently.
Since internally is caught and re-thrown from a different thread than the current, it doesn't preserve it's nature of " special application killing " exception in the shifting logic.
In addition, if it was to re-throw it, you wouldn't even been able to Thread.ResetAbort()
as it works on the current thread and will not act on the one that actually aborted.
MSDN documentation explains this, too here :
If any of these exceptions are unhandled in threads created by the common language runtime, the exception terminates the thread, but the common language runtime does not allow the exception to proceed further.
If these exceptions are unhandled in the main thread, or in threads that entered the runtime from unmanaged code, they proceed normally, resulting in termination of the application.
My guess on the rationale behind this is: ThreadAbortException
is re-thrown to avoid stubborn threads to try and stay alive when they shouldn't, but letting it flow and kill also other different threads would probably be quite a bad idea and cause unexpected behaviour.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.