Thread.Abort() 并在 finally 之后延迟

Posted

技术标签:

【中文标题】Thread.Abort() 并在 finally 之后延迟【英文标题】:Thread.Abort() and delay after finally 【发布时间】:2014-10-22 22:14:45 【问题描述】:

当调用 Thread.Abort() 并且该线程正在执行 finally 块时,线程不会中止,直到 finally 块完成。但是,正如我所见,ThreadAbortException 不是在 finally 块结束之后生成的,而是在一些延迟之后生成的:

private static volatile int val1 = 0;

public static void Func1()

    try
    
    
    finally
    
        Thread.Sleep(5000);
    
    //Func2();

    while (true)
        val1++;


public static void Main()

    var thread = new Thread(Func1);
    thread.Start();

    Thread.Sleep(1000);

    thread.Abort();
    thread.Join();

    Console.WriteLine(val1);  // val1 is non-zero!

在此示例中,Main() 末尾的 val1 将非零。为什么会这样?

如果我取消注释对 Func2() 的调用(Func2 是任何方法,可能为空),val1 的输出将显示“0”。为什么添加方法会影响线程中止点?

【问题讨论】:

有趣的问题,但是在没有附加调试器的发布模式下,我可以得到一个非零数字 val1Func2() 未注释的空函数。在发布时附加调试器或在没有调试器的情况下调试时都给我 0。 Thread.Abort 很糟糕,非常很糟糕。它使您的应用程序处于不可预测的状态,并且您在使用后将无法依赖关于程序行为的常见假设。你应该avoid不惜一切代价打电话给它。 【参考方案1】:

在这种情况下,用lock 包围增量可能很有用。锁控制对该成员的访问。 Abort 方法只是通知线程“嘿,你现在可以停止”,但它不会杀死线程。所以线程可以在Abort 之后存活片刻。访问lock 线程检查它是否被中止并在需要时自行杀死它。

这是您编辑的示例代码

using System;
using System.Threading;

namespace ConsoleApp1

    class Program
    
        private static volatile int val1 = 0;
        static Object Locker = new Object();

        public static void Func1()
        
            try
            
            
            finally
            
                Thread.Sleep(5000);
            
            //Func2();

            while (true)
            
                //Lock the access to the member
                lock (Locker)
                    val1++;
            
        

        public static void Main()
        
            var thread = new Thread(Func1);
            thread.Start();

            Thread.Sleep(1000);
            //Not needed. Just to make sure
            lock (Locker)
            
                thread.Abort();
                thread.Join();
            

            Console.WriteLine(val1);  // val1 is non-zero!
                                      // Now it is zero
            Console.ReadLine();
        
    

抱歉回复晚了

【讨论】:

Thread.Abort 可以中止锁定区域中间的线程。如果发生这种情况,它不会释放锁。这是非常危险的建议。 它将释放锁,导致锁的释放是在 finally 块内部的,如果线程在 finally 的一种情况下中止,finally 块将始终执行,因为线程实际上被杀死了一个线程中止异常。您也可以只处理该异常。检查this 这并不总是正确的。如果线程在finally 块期间 中止,它可以跳过释放锁。请参阅 here 的讨论,其中有一些实际设计 C# 和 .NET 的人。

以上是关于Thread.Abort() 并在 finally 之后延迟的主要内容,如果未能解决你的问题,请参考以下文章

可以像中止一个Thread(Thread.Abort方法)一样中止一个Task吗?

Thread.Abort() 方法冻结

.NET Thread.Abort 再次

在没有“Thread.Abort()”的情况下立即停止 C# 线程

如何抑制 thread.abort() 错误 C#?

Thread.Abort 方法