如何在WPF中停止线程
1. Abort的非及时性
使用多线程经常会遇到一个问题,如何停止这个Thread?在WPF中提供了Abort方法,但MSDN却告诉我们:
线程不一定会立即中止,或者根本不中止。 如果线程在作为中止过程的一部分被调用的 finally 块中做非常大量的计算,从而无限期延迟中止操作,则会发生这种情况。
先看下面一段代码:
1 | public partial class MainWindow : Window |
在运行中点击Button,则可能得到的输出如下:
可以看到Abort后线程仍在运行,然后才停止,输出的结果是多变的,有可能Abort之后再无输出,也有可能输出多行,但都能说明一个问题:使用abort不能立即终止一个thread.
那么到这里,需要先认识一下究竟Abort是什么?
简单来说,Abort是一个标识或者信号,调用它会引发ThreadAbortException,Abort会去请求终止thread,但这不是立即的。
改动一下代码再看看结果:
1 | private void Button_Click(object sender, RoutedEventArgs e) |
点击Button执行Abort后立即输出thread的状态,发现IsAlive=True
,ThreadState=Running
,当然也有可能是IsAlive=False
,ThreadState=Aborted
,因为Abort是不稳定的。然后停一段时间确保thread被终止再点击Button1输出thread的状态,此时IsAlive=False
,ThreadState=Aborted
.
2. Abort和Join同时使用的意义
由于abort之后获取到的thread的信息是不稳定的,所以可能会想到用Join,它的作用是:
使用此方法确保线程已终止。 如果线程不终止,则调用方将无限期阻塞。 如果调用 Join 时该线程已终止,此方法将立即返回。
也就是说如果我们使用Abort之后再加上Join,那么Join之后的thread肯定是Aborted.
修改一下Button的代码:
1 | private void Button_Click(object sender, RoutedEventArgs e) |
没有加入Join之前,输出的IsAlive和ThreadState可能是多种情况的,加入之后,输出的一定是IsAlive=False
,ThreadState=Aborted
.
需要注意的是Join的作用并不是终止thread,它只是等待thread直到thread执行完成。
3. 如何停止线程
如果考虑让一个thread先停止,然后需要的时候再执行,那么使用abort是很不明智的。一般来说只有当应用程序退出,我们才需要把thread彻底关闭,也就是这时候才用到abort。对于停止线程的需求,可以通过信号来解决:
1 | public partial class MainWindow : Window |
上面的例子通过信号量来控制thread中的内容是否执行,在实际应用中,如果一个thread中的内容可能再也不会用到,那么对于这一类情况,使用abort和join;如果这个thread只是临时停止,还会再用到,那么使用信号控制就可以了。
如何在WPF中停止线程