改善C#程序的建议7:正确停止线程
开发者总尝试对自己的代码有更多的控制。“让那个还在工作的线程马上停止下来”就是诸多要求中的一种。然而事与愿违,这里面至少存在两个问题:
第一个问题是:正如线程不能立即启动一样,线程也并不能说停就停。无论采用何种方式通知工作线程需要停止,工作线程都会忙完手头最紧要的活,然后在它觉得合适的时候退出。以最传统的Thread.Abort方法为例,如果线程当前正在执行的是一段非托管代码,那么CLR就不会抛出ThreadAbortException,只有当代码继续回到CLR中时,才会引发ThreadAbortException。当然,即便是在CLR环境中,ThreadAbortException也不会立即引发。
其次,正确停止线程,不在于调用者采取了什么行为(如最开始的Thread.Abort()方法),而更多依赖于工作线程是否能主动响应调用者的停止请求。大体机制是,如果线程需要被停止,那么线程自身就得负责开放给调用者这样的接口:Cancled,然后线程在工作的同时,还得以某种频率检测Cancled标识,若检测到Cancled,线程自己负责退出。
FCL现在为我们提供了标准的取消模式:协作式取消(Cooperative Cancellation)。协作式取消的机制就是上文提到的机制。下面是一个最基础的协作式取消的样例:
CancellationTokenSource cts =new CancellationTokenSource(); Thread t =new Thread(() => { while (true) { if (cts.Token.IsCancellationRequested) { Console.WriteLine("线程被终止!"); break; } Console.WriteLine(DateTime.Now.ToString()); Thread.Sleep(); } }); t.Start(); Console.ReadLine(); cts.Cancel();
调用者使用CancellationTokenSource的Cancle方法通知工作线程退出。工作线程则以大致1000毫秒的频率一边工作,一边检查是否有外界传入进来的Cancel信号。若有这样的信号,则负责退出。可以看到,在正确停止线程的机制中,真正起到主要作用的是线程本身。样例中的工作代码比较简单,不过也足以说明问题。更复杂的计算式的工作,也应该以这样的一种方式,妥善而正确地处理退出。
协作式取消中的关键类型是CancellationTokenSource。它有一个关键属性Token,Token是一个名为CancellationToken的值类型。CancellationToken继而进一步提供了布尔值的属性IsCancellationRequested作为需要取消工作的标识。CancellationToken还有一个方法尤其值得注意,那就是Register方法。它负责传递一个Action委托,在线程停止的时候被回调,使用方法如:
cts.Token.Register(() => { Console.WriteLine("工作线程被终止了。"); });
本建议中的例子使用Thread进行了演示,使用ThreadPool也是一样的模式,这里就不再赘述。后面我们还会讲到任务Task,它依赖于CancellationTokenSource和CancellationToken完成了所有的取消控制。
微信扫一扫,关注最课程(www.zuikc.com),获取更多我的文章,获取软件开发每日一练
之前的话题:
改善C#程序的建议6:在线程同步中使用信号量改善C#程序的建议5:引用类型赋值为null与加速垃圾回收改善C#程序的建议4:C#中标准Dispose模式的实现改善C#程序的建议3:在C#中选择正确的集合进行编码改善C#程序的建议2:C#中dynamic的正确用法改善C#程序的建议1:非用ICloneable不可的理由
改善C#程序的建议7:正确停止线程的更多相关文章
- 改善C#程序的建议6:在线程同步中使用信号量
原文:改善C#程序的建议6:在线程同步中使用信号量 所谓线程同步,就是多个线程之间在某个对象上执行等待(也可理解为锁定该对象),直到该对象被解除锁定.C#中对象的类型分为引用类型和值类型.CLR在这两 ...
- [No000017D]改善C#程序的建议6:在线程同步中使用信号量
所谓线程同步,就是多个线程之间在某个对象上执行等待(也可理解为锁定该对象),直到该对象被解除锁定.C#中对象的类型分为引用类型和值类型.CLR在这两种类型上的等待是不一样的.我们可以简单的理解为在CL ...
- 改善C#程序的建议10:用Parallel简化Task
在命名空间System.Threading.Tasks下,有一个静态类Parallel简化了在同步状态下的Task的操作.Parallel主要提供了3个有用的方法:For.ForEach.Invoke ...
- 改善C#程序的建议8:避免锁定不恰当的同步对象
原文:改善C#程序的建议8:避免锁定不恰当的同步对象 在C#中让线程同步的另一种编码方式就是使用线程锁.所谓线程锁,就是锁住一个资源,使得应用程序只能在此刻有一个线程访问该资源.可以用下面这句不是那么 ...
- 编写高质量代码改善C#程序的157个建议——建议77: 正确停止线程
建议77: 正确停止线程 开发者总尝试对自己的代码有更多的控制.例如,“让那个还在工作的线程马上停止下来”.然而,并非我们想怎样就可以怎样的,这至少涉及两个问题. 第一个问题 正如线程不能立即启动一样 ...
- [No000017E]改善C#程序的建议7:正确停止线程
开发者总尝试对自己的代码有更多的控制.“让那个还在工作的线程马上停止下来”就是诸多要求中的一种.然而事与愿违,这里面至少存在两个问题: 第一个问题是:正如线程不能立即启动一样,线程也并不能说停就停.无 ...
- [转]改善C#程序的建议4:C#中标准Dispose模式的实现
需要明确一下C#程序(或者说.NET)中的资源.简单的说来,C#中的每一个类型都代表一种资源,而资源又分为两类: 托管资源:由CLR管理分配和释放的资源,即由CLR里new出来的对象: 非托管资源:不 ...
- 改善C#程序的建议1:非用ICloneable不可的理由
原文:改善C#程序的建议1:非用ICloneable不可的理由 好吧,我承认,这是一个反标题,实际的情况是:我找不到一个非用ICloneable不可的理由.事实上,接口ICloneable还会带来误解 ...
- 正确停止线程的方式三 使用Thread类中的内置的中断标记位-----------不熟悉
package charpter10; public class Processor implements Runnable { @Override public void run() { for ( ...
随机推荐
- ios tableView那些事
iOS开发很重要的一个功能就是tableView,可以说熟练使用tableView是iOS开发必修的课程,网上很多相关介绍,推荐一个博客参考一下: http://blog.csdn.net/lengs ...
- MAC终端:如何调整字体大小和终端样式
1.字体 进入终端后comman键和+键的组合可以增大显示 2.样式
- TensorFlow 学习(十一)—— 正则(regularizer)
正则作用的对象是目标函数,如图对均方误差使用 ℓ2 正则: loss = tf.reduce_mean(tf.square(y-y_) + tf.contrib.layers.l2_regulariz ...
- 【b603】作业调度方案
Time Limit: 1 second Memory Limit: 50 MB [问题描述] 我们现在要利用m台机器加工n个工件,每个工件都有m道工序,每道工序都在不同的指定的机器上完成.每个工件的 ...
- js Map 遍历
1. 在知道的key的情况下遍历map自然就跟数组一样的访. 2.在不知道key的情况下遍历map(此情况更多吧) 2.1 for(var key in Map){ }; //第一种 ...
- 【codeforces 789C】Functions again
[题目链接]:http://codeforces.com/contest/789/problem/C [题意] 看式子. [题解] 考虑最后的答案区间; 如果那个区间是从奇数位置的数字开始的; 那么奇 ...
- 【18.40%】【codeforces 631D】Messenger
time limit per test 2 seconds memory limit per test 512 megabytes input standard input output standa ...
- Visual Studio - 为默认模板添加版权信息
转自:http://www.cnblogs.com/easyzikai/archive/2012/10/14/2723328.html 和 http://www.cnblogs.com/eagle19 ...
- Android无线调试——抛开USB数据线
开发Android的朋友都知道,真机调试需要把手机与PC相连,然后把应用部署到真机上进行安装和调试.长长的USB线显得很麻烦,而且如果需要USB接口与其他设备连接的话显得很不方便.今天介绍一种不通过U ...
- 在嵌入式程序中QT去掉鼠标指针
在像arm的QT编程当中,一般都是使用触摸来操作,当是我们运行程序的时候会发现总是有个鼠标箭头在那里,下面介绍种方法将其给去掉.这样就漂亮多了.在main()函数加入 #include <QWS ...