开发者总尝试对自己的代码有更多的控制。“让那个还在工作的线程马上停止下来”就是诸多要求中的一种。然而事与愿违,这里面至少存在两个问题:

第一个问题是:正如线程不能立即启动一样,线程也并不能说停就停。无论采用何种方式通知工作线程需要停止,工作线程都会忙完手头最紧要的活,然后在它觉得合适的时候退出。以最传统的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(
1000
);
}
});
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完成了所有的取消控制。

[No000017E]改善C#程序的建议7:正确停止线程的更多相关文章

  1. 改善C#程序的建议6:在线程同步中使用信号量

    原文:改善C#程序的建议6:在线程同步中使用信号量 所谓线程同步,就是多个线程之间在某个对象上执行等待(也可理解为锁定该对象),直到该对象被解除锁定.C#中对象的类型分为引用类型和值类型.CLR在这两 ...

  2. [No000017D]改善C#程序的建议6:在线程同步中使用信号量

    所谓线程同步,就是多个线程之间在某个对象上执行等待(也可理解为锁定该对象),直到该对象被解除锁定.C#中对象的类型分为引用类型和值类型.CLR在这两种类型上的等待是不一样的.我们可以简单的理解为在CL ...

  3. 改善C#程序的建议7:正确停止线程

    原文:改善C#程序的建议7:正确停止线程 开发者总尝试对自己的代码有更多的控制.“让那个还在工作的线程马上停止下来”就是诸多要求中的一种.然而事与愿违,这里面至少存在两个问题: 第一个问题是:正如线程 ...

  4. 改善C#程序的建议10:用Parallel简化Task

    在命名空间System.Threading.Tasks下,有一个静态类Parallel简化了在同步状态下的Task的操作.Parallel主要提供了3个有用的方法:For.ForEach.Invoke ...

  5. 改善C#程序的建议8:避免锁定不恰当的同步对象

    原文:改善C#程序的建议8:避免锁定不恰当的同步对象 在C#中让线程同步的另一种编码方式就是使用线程锁.所谓线程锁,就是锁住一个资源,使得应用程序只能在此刻有一个线程访问该资源.可以用下面这句不是那么 ...

  6. 编写高质量代码改善C#程序的157个建议——建议77: 正确停止线程

    建议77: 正确停止线程 开发者总尝试对自己的代码有更多的控制.例如,“让那个还在工作的线程马上停止下来”.然而,并非我们想怎样就可以怎样的,这至少涉及两个问题. 第一个问题 正如线程不能立即启动一样 ...

  7. [转]改善C#程序的建议4:C#中标准Dispose模式的实现

    需要明确一下C#程序(或者说.NET)中的资源.简单的说来,C#中的每一个类型都代表一种资源,而资源又分为两类: 托管资源:由CLR管理分配和释放的资源,即由CLR里new出来的对象: 非托管资源:不 ...

  8. 改善C#程序的建议1:非用ICloneable不可的理由

    原文:改善C#程序的建议1:非用ICloneable不可的理由 好吧,我承认,这是一个反标题,实际的情况是:我找不到一个非用ICloneable不可的理由.事实上,接口ICloneable还会带来误解 ...

  9. 正确停止线程的方式三 使用Thread类中的内置的中断标记位-----------不熟悉

    package charpter10; public class Processor implements Runnable { @Override public void run() { for ( ...

随机推荐

  1. 12C -- ORA-01017

    本地使用使用sqlplus,尝试连接12.2数据库报错: 在另外一台服务器上,使用sqlplus连接该库,可以成功: 解决方案: 根据MOS文档id:207303.1看出,只有11.2.0.3之上的客 ...

  2. C#:文件夹匹配

    //文件夹匹配:对比文件夹,相同的目录结构.所有文件名称小写相同,制定文件外的MD5值相同 ,则两个文件夹匹配成功! /// <summary> /// 批量匹配书籍H5资源包 /// & ...

  3. 理顺FFT

    DFT(Discrete Fourier Transform):离散傅立叶变换 直观的计算DFT算法复杂度为O(N*N). FFT(Fast Fourier Transformation):快速傅立叶 ...

  4. [android开发教程] 一个神奇的Demo 帮你掌握所有android控件

    (本文内容来源:http://www.eoeandroid.com/thread-182392-1-1.html  转载请注明出处!) 2.jpg (23.78 KB, 下载次数: 0) 下载附件   ...

  5. 微信小程序场景值

    场景值 基础库 1.1.0 开始支持,低版本需做兼容处理 当前支持的场景值有: 场景值ID 说明 1001 发现栏小程序主入口 1005 顶部搜索框的搜索结果页 1006 发现栏小程序主入口搜索框的搜 ...

  6. [Android]Android数据的四种存储方式

    存储方式 Android提供以下四种存储方式: SharePreference SQLite File ContentProvider Android系统中数据基本都是私有的,一般存放在“data/d ...

  7. Android Launcher分析和修改5——HotSeat分析

    今天主要是分析一下Launcher里面的快捷方式导航条——HotSeat,一般我们使用手机底下都会有这个导航条,但是如果4.0的Launcher放到平板电脑里面运行,默认是没有HotSeat的,刚好我 ...

  8. javascript and jquery 代码块

    1.5秒隐藏 (setTimeout ) setTimeout( function(){ $('.ad_midd').slideUp(); } , 5000 )

  9. Java知多少(96)绘图之设置字型和颜色

    Java绘图中,显示文字的方法主要有三种:(1)drawString(String str,int x,int y):在指定的位置显示字符串.(2)drawChars(char data[],int ...

  10. Android集成Google地图详细步骤记录

    先贴下Google官方的地图demo地址:https://github.com/googlemaps/android-samples 那么接下来第一步,申请Google的API key. 使用谷歌账号 ...