• 建议77: 正确停止线程


    开发者总尝试对自己的代码有更多的控制。例如,“让那个还在工作的线程马上停止下来”。然而,并非我们想怎样就可以怎样的,这至少涉及两个问题。

    第一个问题 正如线程不能立即启动一样,线程也并不是说停就停的。无论采用何种方式通知工作线程需要停止,工作线程都会忙完手头最紧要的活,然后在它觉得合适的时候退出。以最传统的Thread.Abort方法为例,如果线程当前正在执行的是一段非托管代码,那么CLR就不会抛出ThreadAbortException,只有当代码继续回到CLR中时,才会引发ThreadAbortException。当然,即便是在CLR环境中,ThreadAbortException也不会立即引发。

    第二个问题 要正确停止线程,不在于调用者采取了什么行为(如最开始的Thread.Abort()方法),而更多依赖于工作线程是否能主动响应调用者的停止请求。大体机制是,如果线程需要被停止,那么线程自身就应该负责给调用者开放这样的接口:Cancled。线程在工作的同时,还要以某种频率检测Cancled标识,若检测到Cancled,线程自己才会负责退出。

    FCL现在为我们提供了标准的取消模式:协作式取消(Cooperative Cancellation)。协作式取消的机制就是上文第二个问题中所提到的机制。下面是一个最基础的协作式取消的示例:

    复制代码
    static void Main(string[] args)
    {
        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.ReadKey();
        cts.Cancel();
        Console.ReadKey();
    }
    复制代码

    调用者使用CancellationTokenSource的Cancel方法通知工作线程退出。工作线程则以大约1000ms的频率一边工作,一边检查是否有外界传入的Cancel信号,若有这样的信号,则退出。可以看到,在正确停止线程的机制中,真正起到主要作用的是线程本身。示例中的工作代码比较简单,但足以说明问题。更复杂的计算式工作,也应该以这样的一种方式,妥善而正确地处理退出。

    协作式取消中的关键类型是CancellationTokenSource。它有一个关键属性Token,Token是一个名为CancellationToken的值类型。CancellationToken继而进一步提供了布尔值的属性IsCancellationRequested作为需要取消工作的标识。CancellationToken还有一个方法尤其值得注意,那就是Register方法。它负责传递一个Action委托,在线程停止的时候被回调,使用方法如下:

    cts.Token.Register(() =>
    {
        Console.WriteLine("工作线程被终止了。");
    });

    本例使用Thread进行了演示,如果使用ThreadPool也是一样的模式,这里就不再赘述。后面还会讲到任务Task,它依赖于CancellationTokenSource和CancellationToken完成了所有的取消控制。

    转自:《编写高质量代码改善C#程序的157个建议》陆敏技

    以下是本书作者的相关信息,在此感谢作者的辛勤奉献!

    原文作者:陆敏技

    书名:编写高质量代码:改善C#程序的157个建议

    作者Blog:www.cnblogs.com/luminji

    转自https://www.cnblogs.com/Niko12230/articles/5391246.html

  • 相关阅读:
    nodeJS操作mongoDB常用api
    git命令
    Scala笔记(1)——基本知识
    Akka Java 中文文档
    训练:用gfsh执行常见的任务
    https://confluence.jnj.com/display/AAIM/Enterprise+Agile+Data+Services
    gfsh操作
    java知识
    maven使用之烦人的.lastUpdated文件
    idea相关操作
  • 原文地址:https://www.cnblogs.com/asdyzh/p/9876277.html
Copyright © 2020-2023  润新知