c# - 如何强制关闭运行它自己的线程的后台工作者

Posted

技术标签:

【中文标题】c# - 如何强制关闭运行它自己的线程的后台工作者【英文标题】:c# - How to force closing of background worker that run it own threads 【发布时间】:2014-09-29 09:38:08 【问题描述】:

我有 wpf 应用程序,我们称之为A-appA-app 与后台工作人员一起运行异步 B-methodB-method 位于不同的项目中,它为 B-method init 部分创建了几个线程。

用户可以要求运行B-method,也可以要求取消运行并重新启动。 问题是,如果它在初始化时被取消,运行B-method 的后台工作程序将被取消,但线程不会。 重新启动会创建更多的线程,这些线程不能与之前运行的线程同时工作,并且会产生一些错误。

Threads 方法主要是在等待。

如何停止B-method 并取消它创建的线程?

不同的 AppDomain 是否有任何帮助? (而不是关闭整个应用程序域?)如果是,那应该怎么做? 有没有更好的办法?

更多详情:

B 方法在某些设备(可能很多)上运行测试。该方法的初始化是连接到设备 - i/o - 所以大部分时间都花在等待上(这就是我们决定使连接初始化并行的原因)。从 2 个不同线程连接到同一设备可能会导致问题.

【问题讨论】:

是的,AppDomain 可能是最好的。如何卸载已被多次询问(请参阅此处右侧的列) AppDomain 和线程的概念是正交的。卸载 AppDomain 不是取消工作人员的好方法。 【参考方案1】:

我建议您根本不要创建线程,而是使用 TaskScheduler 并使用并行任务库:

http://msdn.microsoft.com/en-us/library/dd997402%28v=vs.110%29.aspx

TaskScheduler 本身是 ThreadPool 的包装器,它处理线程。它甚至可以做诸如 WorkStealing、Task Inling 之类的东西。

最好从这里开始:http://msdn.microsoft.com/en-us/library/dd997402%28v=vs.110%29.aspx

另一种方法是使用 CancallionToken 启动任务,这使您可以取消任务。见这里:http://msdn.microsoft.com/en-us/library/dd537607%28v=vs.110%29.aspx

编辑:好的,没有 TPL,阻塞线程。这基本上只剩下 Thread.Abort。 这个乱七八糟,但是没有完美的世界,所以把Form想象成Application A,ClassB就是Application B:

public partial class MainWindow : Window

    Thread _threadA;
    Thread _threadB;
    Thread _threadC;

    ClassB b1 = new ClassB();
    ClassB b2 = new ClassB();
    ClassB b3 = new ClassB();

    public MainWindow()
    
        InitializeComponent();

        _threadA = new Thread(() => b1.DoSomeWork("A"));
        _threadB = new Thread(() => b2.DoSomeWork("B"));
        _threadC = new Thread(() => b3.DoSomeWork("C"));
    

    private void btnStartWork_Click(object sender, RoutedEventArgs e)
    
        _threadA.Start();
        _threadB.Start();
        _threadC.Start();
    

    private void btnStopThreadA_Click(object sender, RoutedEventArgs e)
    
        AbortThreadA();
    

    private void btnStopThreadB_Click(object sender, RoutedEventArgs e)
    
        AbortThreadB();
    

    private void btnStopThreadC_Click(object sender, RoutedEventArgs e)
    
        AbortThreadC();
    

    private void AbortThreadA()
    
        _threadA.Abort();
    

    private void AbortThreadB()
    
        _threadB.Abort();
    

    private void AbortThreadC()
    
        _threadC.Abort();
    

    private void btnStopAll_Click(object sender, RoutedEventArgs e)
    
        AbortThreadA();
        AbortThreadB();
        AbortThreadC();
    




class ClassB

    public void DoSomeWork(string threadIdentifier)
    
        try
         
            string preWorkString = "Work work Okeydokey. Thread: " + threadIdentifier;
            string postWorkString = "Job's Done. Thread: " + threadIdentifier;

            while (true)
            
                System.Diagnostics.Debug.WriteLine(preWorkString);
                Thread.Sleep(5000);
                System.Diagnostics.Debug.WriteLine(postWorkString);
            
        
        catch (ThreadAbortException)
        
            System.Diagnostics.Debug.WriteLine("Thread aborted. Thread: " + threadIdentifier);
            Thread.ResetAbort();
        
    

需要ResetAbort,否则错误会冒泡。

这是一个可能的解决方案吗?

【讨论】:

由于使用旧环境,我无法升级 .Net 版本,所以这不是一个选项(我认为任务来自 .Net 4)。只是出于好奇,有没有比线程更好的取消任务的方法?它只是一个包装器,线程大多处于等待状态。 TaskScheduler 只是线程池的包装器。您可以让 ThreadPool 处理线程。您基本上在开始时创建大量线程并让池在它们之间进行处理。我想说直接创建新线程几乎不是一个好主意。 我明白,问题仍然是关于取消的。使用池而不是直接启动线程有什么不同?取消有何不同? 编辑我的帖子以获得另一个解决方案【参考方案2】:

你是否拥有 B 方法(即你能改变它吗?)

我假设 B 方法本质上是不可取消的,而您只是取消在模块 A 中调用它的后台工作人员?

B 方法需要更改为可取消或可重入。通过重入,我的意思是它将允许对其自身进行多次调用,并将重用任何已经在进行中的现有 init 序列。

【讨论】:

B 方法是长期测试动作的起点(它调用许多其他方法,这里大部分时间也是 I/O 和等待)

以上是关于c# - 如何强制关闭运行它自己的线程的后台工作者的主要内容,如果未能解决你的问题,请参考以下文章

如何检测应用程序何时在后台 Swift 中强制关闭 [重复]

C# 线程运行完之后自己会不会释放掉

关于C# WPF线程后台运行的

如何在c#控制台应用程序中自动(强制)停止当前线程[重复]

Macbook怎么强制关闭后台程序?Macbook强制关闭后台程序的方法

c# 一个程序关闭,如果有前台线程还在运行,当前台线程运行完是不是会关闭?还是一直存在?