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

Posted

技术标签:

【中文标题】在没有“Thread.Abort()”的情况下立即停止 C# 线程【英文标题】:Stop C# thread immediately without "Thread.Abort()" 【发布时间】:2021-12-17 12:48:31 【问题描述】:
public class Worker

    private CancellationTokenSource cts;
    private Thread t;

    public Worker()
    
        cts = new CancellationTokenSource();
        t = new Thread(() =>  ThreadTask(cts.Token); );
    

    ~Worker()
    
        cts.Dispose();
    

    private void ThreadTask(CancellationToken ct)
    
        try
        
            while (true)
            
                if (ct.IsCancellationRequested)
                
                    Debug.WriteLine("Cancelllation requested");
                    break;
                

                // long task 1
                Debug.WriteLine("Task 1 completed");
                Thread.Sleep(2000);
                // long task 2
                Debug.WriteLine("Task 2 completed");
                Thread.Sleep(2000);
                // long task 3
                Debug.WriteLine("Task 3 completed");
                Thread.Sleep(2000);
                // long task 4
                Debug.WriteLine("Task 4 completed");
                Thread.Sleep(2000);
                Debug.WriteLine("All tasks completed");
            
        
        catch (Exception ex)
        
            Debug.WriteLine("Thread exception: " + ex.ToString());
        
        finally
        
            // cleanup
            Debug.WriteLine("Thread cleanup");
        
    

    public void Start()
    
        t.Start();
    

    public void Stop()
    
        cts.Cancel();
    

我想知道是否可以在线程完成执行之前中断它。

例如,在上面描述的代码中,当调用函数Stop()时,线程将在执行完成后停止,我想更快地停止它,例如在“长任务”之间甚至在@ 987654324@.

解决方案是在调用Stop() 时可能会在任务线程中抛出异常,例如Thread.Abort(),但Thread.Abort() 在Net 6.0 上不起作用,我该怎么做?

环境:

C# 网络 6.0 Windows 10 x64 Visual Studio 2019 和 Visual Studio 2022

【问题讨论】:

您应该切换到异步方法并使用await Task.Delay(2000, ct);。但是,没有简单的方法可以停止 CPU 密集型任务。该任务需要定期检查是否取消。 看看there。否则(AFAIK)你需要在任务之间实现某种合作(取消令牌、协程......) Thread.Abort() 可用时,它不能解决您的问题。调用 Abort 仅在您尝试强制退出应用程序时有用,因为调用它可能会破坏 .NET 运行时本身。调用Abort 后,您不能依赖您的程序正常工作。唯一真正的答案是让线程合作停止。 感谢所有 cmets。 @JeremyLakeman 你的建议很有帮助,即使没有 Task.Delay(2000, ct).Wait() 的异步方法,我什至设法使用它。 @PedroDuarte - 请不要.Wait() 处理此类任务。您应该始终使用await 【参考方案1】:

您可以使用Thread.Interrupt 方法。当前 .NET 平台支持此 API。

中断处于WaitSleepJoin 线程状态的线程。

如果该线程当前没有被阻塞在等待、睡眠或加入状态,它将在下一次开始阻塞时被中断。

ThreadInterruptedException 在被中断的线程中抛出,但直到线程阻塞。如果线程从不阻塞,则永远不会抛出异常,因此线程可能会在不被中断的情况下完成。

您必须在ThreadStart 委托的主体内处理可能的ThreadInterruptedException,否则在调用Interrupt 时进程可能会崩溃。或者您可以使用通用的 catch (Exception) 处理程序来处理所有异常,就像您目前正在做的那样。

【讨论】:

使用Thread.Interrupt() 是一个非常好的选择,感谢您的建议。

以上是关于在没有“Thread.Abort()”的情况下立即停止 C# 线程的主要内容,如果未能解决你的问题,请参考以下文章

Thread.Abort()方法冻结

如何在 C# 中立即杀死一个线程?

立即终止Sleep的线程

强制终止由 Parallel.ForEach 生成的线程 [重复]

Thread.Abort() 方法冻结

Thread.Abort 的安全异常