ThreadAbortException最后可以跳过吗?

问题描述 投票:0回答:3

我读到的所有内容都声称线程上的中止将在从 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());
}

运行此程序时我发现控制台从未提及进入finally块。应用程序在 .abort 调用后继续运行,就好像根本没有finally 块一样。难道我做错了什么?在最终写入控制台之前,不应该将控制传递给finally块,或者执行顺序仍然是finally位于单独线程或其他东西中这一事实的函数吗?

c# multithreading abort finally
3个回答
8
投票

文档说

ThreadAbortException
是一种可以捕获的特殊异常,但它会在catch块末尾自动再次引发。当引发此异常时,运行时会在结束线程之前执行所有的finally 块。因为线程可以在finally块中进行无限计算或调用Thread.ResetAbort来取消中止,所以不能保证线程将永远结束。

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

或者由于线程并行运行而存在竞争条件:主线程在旋转的测试线程可以输出finally数据之前完成(异常是昂贵的,并且需要时间才能到达catch或finally块)。


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());

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


3
投票
finally

控制台应用程序(假设它是一个)可能在 

finally

块运行之前退出(因为调用

Thread.Abort()
后没有等待)。
    

© www.soinside.com 2019 - 2024. All rights reserved.