ThreadAbortException最终可以跳过吗?

use*_*768 5 c# multithreading finally abort

我读过的所有内容声称线程中止将在从ThreadAbortException结束之前执行finally块.我想确认这一点,以便我可以计划如何处理可以无限期挂起的某些第三方代码.但是下面的测试让我感到困惑:

public void runTest(DateTime deadline)
{
    testThread = new Thread(() => 
    {
        try 
        {
            Console.WriteLine("test thread started at " + DateTime.Now.ToShortTimeString());
            while (true) { }
        }
        finally
        {
            Console.WriteLine("test thread entered FINALLY at " + DateTime.Now.ToShortTimeString());
            while (true) { }
        }
    });
    testThread.Start();
    while (testThread.IsAlive && deadline.Subtract(DateTime.Now).TotalSeconds > 0)
    {
        Console.WriteLine("main thread while loop " + DateTime.Now.ToShortTimeString());
        Thread.Sleep(10000);
    }
    if (testThread.IsAlive)
        testThread.Abort();
    Console.WriteLine("main thread after abort call " + DateTime.Now.ToShortTimeString());
}
Run Code Online (Sandbox Code Playgroud)

我在运行时发现的是控制台从未提到进入finally块.应用程序在.abort调用之后继续,好像根本没有finally块.难道我做错了什么?在到达最终写入控制台之前,不应该控制传递给finally块,还是执行顺序仍然是最终在单独的线程中的事实的函数?

Han*_*ney 7

文档说:ThreadAbortException是一个可以捕获的特殊异常,但它会在catch块结束时自动再次引发.引发此异常时,运行时会在结束线程之前执行所有finally块.因为线程可以在finally块做一个无限的计算或致电Thread.ResetAbort取消中止,也不能保证该线程将永远结束.

我很确定您的线程被转储,因为您退出方法并丢失对它的引用,因此它被垃圾收集器收集.尝试将testThread变量作为类的字段成员,看看会发生什么.

那个,或者你有一个竞争条件,因为线程并行运行:主线程在spun-up测试线程可以输出finally数据之前完成(例外是昂贵的,需要时间来达到catch或finally块).

  • 通常不会收集正在运行的线程.请参阅:http://stackoverflow.com/questions/81730/what-prevents-a-thread-in-c-sharp-from-being-collected (3认同)

Zve*_*niy 5

工作线程函数中的finally块在与主线程并行的工作线程上执行.这是竞争条件.你不能分清最后的工作线程或者中止调用之后的主线程代码.如果你需要同步中止,那么你必须这样做:

        if (testThread.IsAlive)
        {
            testThread.Abort();

            bool blnFinishedAfterAbort = testThread.Join(TimeSpan.FromMilliseconds(1000));
            if (!blnFinishedAfterAbort)
            {
                Console.WriteLine("Thread abort failed.");
            }
        }
        Console.WriteLine("main thread after abort call " + DateTime.Now.ToShortTimeString());
Run Code Online (Sandbox Code Playgroud)

请记住,如果您启用了遗留异常处理(请参阅http://msdn.microsoft.com/en-us/library/ms228965.aspx)并且您指定了AppDomain_UnahandledException事件处理程序,那么ThreadAbortException将导致执行到该处理程序BEFORE工作线程函数中的finally块.这只是在中止线程时应该注意的令人沮丧和意外执行顺序的另一个例子.