c# - 如何强制关闭运行它自己的线程的后台工作者
Posted
技术标签:
【中文标题】c# - 如何强制关闭运行它自己的线程的后台工作者【英文标题】:c# - How to force closing of background worker that run it own threads 【发布时间】:2014-09-29 09:38:08 【问题描述】:我有 wpf 应用程序,我们称之为A-app
。 A-app
与后台工作人员一起运行异步 B-method
。 B-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 中强制关闭 [重复]