• 第七节:利用CancellationTokenSource实现任务取消和利用CancellationToken类检测取消异常。


    一. 传统的线程取消

       所谓的线程取消,就是线程正在执行的过程中取消线程任务。

       传统的线程取消,是通过一个变量来控制,但是这种方式,在release模式下,被优化从cpu高速缓存中读取,而不是从内存中读取,会造成主线程无法执行这一个bug。

     1   {
     2                 var isStop = false;
     3                 var thread = new Thread(() =>
     4                 {
     5                     while (!isStop)
     6                     {
     7                         Thread.Sleep(100);
     8                         Console.WriteLine("当前thread={0} 正在运行", Thread.CurrentThread.ManagedThreadId);
     9                     }
    10                 });
    11                 thread.Start();
    12                 Thread.Sleep(1000);
    13                 isStop = true;
    14 }

     

    PS: 通过上面的代码看可以看出来,传统模式的线程取消,在排除release模式bug的情况下,局限性还是很明显的。比如:当子线程任务取消的那一刻,我想执行另外一项任务;我想延时取消一个线程任务;线程取消的时候抛异常。

      上述这几种情况,我们都要借助单独的类来处理。

    二. CancellationTokenSource实现任务取消 

    1. 取消任务的同时触发一个函数

       利用Cancel方法、Register注册、source.Token标记取消位来实现。

                {
                    CancellationTokenSource source = new CancellationTokenSource();
                    //注册一个线程取消后执行的逻辑
                    source.Token.Register(() =>
                    {
                        //这里执行线程被取消后的业务逻辑.
                        Console.WriteLine("-------------我是线程被取消后的业务逻辑---------------------");
                    });
    
                    Task.Run(() =>
                    {
                        while (!source.IsCancellationRequested)
                        {
                            Thread.Sleep(100);
                            Console.WriteLine("当前thread={0} 正在运行", Thread.CurrentThread.ManagedThreadId);
                        }
                    }, source.Token);
    
                    Thread.Sleep(2000);
                    source.Cancel();
                }

    2. 延时取消

    线程的延时取消有两种方式:

      方案一:CancelAfter方法。

     1         #region 方案一:CancelAfter方法
     2                 {
     3                     CancellationTokenSource source = new CancellationTokenSource();
     4                     //注册一个线程取消后执行的逻辑
     5                     source.Token.Register(() =>
     6                     {
     7                         //这里执行线程被取消后的业务逻辑.
     8                         Console.WriteLine("-------------我是线程被取消后的业务逻辑---------------------");
     9                     });
    10 
    11                     Task.Run(() =>
    12                     {
    13                         while (!source.IsCancellationRequested)
    14                         {
    15                             Thread.Sleep(100);
    16                             Console.WriteLine("当前thread={0} 正在运行", Thread.CurrentThread.ManagedThreadId);
    17                         }
    18                     }, source.Token);
    19 
    20                     Thread.Sleep(2000);
    21                     //4s后自动取消
    22                     source.CancelAfter(new TimeSpan(0, 0, 0, 4));
    23                 } 
    24                 #endregion
    View Code

      方案二:CancellationTokenSource构造函数(不再需要Cancel方法了)。

     1                 {
     2                     //4s后自动取消
     3                     CancellationTokenSource source = new CancellationTokenSource(4000);
     4                     //注册一个线程取消后执行的逻辑
     5                     source.Token.Register(() =>
     6                     {
     7                         //这里执行线程被取消后的业务逻辑.
     8                         Console.WriteLine("-------------我是线程被取消后的业务逻辑---------------------");
     9                     });
    10 
    11                     Task.Run(() =>
    12                     {
    13                         while (!source.IsCancellationRequested)
    14                         {
    15                             Thread.Sleep(100);
    16                             Console.WriteLine("当前thread={0} 正在运行", Thread.CurrentThread.ManagedThreadId);
    17                         }
    18                     }, source.Token);
    19 
    20                     Thread.Sleep(2000);
    21                 } 
    View Code

    3. 组合取消

       利用CreateLinkedTokenSource构建CancellationTokenSource的组合体,其中任何一个体取消,则组合体就取消。 

                {
                    CancellationTokenSource source1 = new CancellationTokenSource();
    
                    //source1.Cancel();
                    CancellationTokenSource source2 = new CancellationTokenSource();
    
                    source2.Cancel();
    
                    var combineSource = CancellationTokenSource.CreateLinkedTokenSource(source1.Token, source2.Token);
    
                    Console.WriteLine("s1={0}  s2={1}  s3={2}", source1.IsCancellationRequested,
                                                             source2.IsCancellationRequested,
                                                             combineSource.IsCancellationRequested);
                }

      上述代码,source1和source2中的任何一个取消,combineSource就会被取消。

    三. CancellationToken类监控取消

       CancellationToken类下ThrowIfCancellationRequested属性,等价于if (XXX.IsCancellationRequested){throw new Exception("报错了");}

       只要取消就报错。

     1             {
     2                 CancellationTokenSource source1 = new CancellationTokenSource();
     3                 CancellationTokenSource source2 = new CancellationTokenSource();
     4                 var combineSource = CancellationTokenSource.CreateLinkedTokenSource(source1.Token, source2.Token);
     5                 source1.Cancel();
     6 
     7                 //if (combineSource.IsCancellationRequested)
     8                 //{
     9                 //    throw new Exception("报错了");
    10                 //}
    11 
    12                 //等价于上面那句话
    13                 try
    14                 {
    15                     combineSource.Token.ThrowIfCancellationRequested();
    16                 }
    17                 catch (Exception)
    18                 {
    19                     Console.WriteLine("报错了");
    20                 }
    21 
    22 
    23                 Console.WriteLine("s1={0}  s2={1}  s3={2}", source1.IsCancellationRequested,
    24                                                          source2.IsCancellationRequested,
    25                                                          combineSource.IsCancellationRequested);
    26             }

  • 相关阅读:
    MSSQL中with(nolock)的用法
    google reader 使用快捷键
    HTML中em标签的用法
    js正则表达式
    C#中lock关键字的用法
    面试反思
    关于IE6.7.8.FF兼容的问题
    C#中DateTime.Now.Ticks的用法和说明
    JS中eval的用法
    这两天面试时不会的笔试题
  • 原文地址:https://www.cnblogs.com/yaopengfei/p/8229175.html
Copyright © 2020-2023  润新知