winform多线程之TASK手动自动取消

本文大部分内容源于网络,https://hk.saowen.com/a/b4232bab0849c85ebd14db611a2a1cf5df69fdf2f32dcf61762acbe89bb065b8,并加入自己的理解。

使用TASK创建的任务能否取消,以及取消后会发生什么。

C#提供的任务取消的方式是“协作式”取消,在构造任务时,需要先构造一个System.Threading.CancellationTaskSource对象,该对象看起来像这样

public  sealed  class CancellationTaskSource:IDisposable{
      public CancellationTokenSource();
      public  void Dispose(); // 释放资源      public  bool IsCancellationRequested{ get ;}
       public CancellationToken Token{ get ;}  
       public  void Cancel(); // 内部调用Cancel并传递false 
     public  void Cancel( bool throwOnFirstException);
 }

CancellationTaskSource对象中含有一个Token,它的类型是CancellationToken,这是一个轻量级值类型,它包含一个私有的对CancellationTaskSource的引用,当构造Task时,需要将这个Token传入,如下所示

static  void Main( string [] args){
      CancelTask​​();
      Console.WriteLine( " Async Run " );
      Console.Read();
  }
  public  static  void CancelTask​​(){
      // 定时1000ms后自动取消任务
      var cancelSource = new CancellationTokenSource( 1000 );
       Task.Run(() =>     {
           // 模拟其他任务
          Thread.Sleep( 4000 );
          Console.WriteLine( " Task over " );
       }, cancelSource.Token);
       cancelSource.Token.Register(() => Console.WriteLine( " Task cancel " ));
  }

运行后可以看到大约1秒后,控制台显示了Task cancel,并且在没有显示Task over。证明任务被取消了。Task.Run()方法的其中一个重载是接受一个CancelToken参数,我们传入的是cancelSource的Token,这表明cancelSource就可以控制Task的取消与否。我的做法是在1秒后自动取消任务,也可以手动调用cancelSource.Cancel()方法来显式取消任务。我在Token上订阅了取消的事件,在任务被取消后,执行我的方法,这里是控制台打印出Task cancel。也可以在任务中,利用“闭包”,将Token传入到任务中,如下

  static  void Main( string [] args){
       CancelTask​​();
       Console.WriteLine( " Async Run " );
       Console.Read();
   }
   public  static  void CancelTask​​(){
       var cancelSource = new CancellationTokenSource ( 1000 );
       Task.Run(() => {
           int count = 0 ;
          for ( int i = 0 ; i <1000 ; i++ )
           {
               if (cancelSource.IsCancellationRequested)
                   break ;
               count+= i;
              Thread.Sleep( 30 );
          }
          Console.WriteLine(count);
      }, cancelSource.Token);
       cancelSource. Token.Register(() => Console.WriteLine( " Task cancel " ));
  }

手动取消有2个方法,一是cancelSource.Cancel(),另一个是cancelSource.CancelAfter(),示例如下

 public  static  void CancelTask​​(){
      var cancelSource = new CancellationTokenSource();
      Task.Run(() =>
      {
          Thread.Sleep( 4000 );
          Console.WriteLine( " Task over " );
      }, cancelSource.Token);
      cancelSource.Token.Register(() => Console.WriteLine( " Task cancel " ));
      // 此处调用cancelSource.Cancel()的话会立即结束任务
       // 该方法会大约1秒后取消任务
    cancelSource.CancelAfter( 1000 );
  }

该示例和上面的在构造函数中传入1000ms的延时是一样的效果,若调用Cancel(),则立刻结束任务。


自动取消的方法在没有循环的情况下可以顺利完成,但在存在无线循环的情况下无法结束(但是Task cancel正常显示)。解决方法是在以上代码中再加入IsCancellationRequested判断,如下:

while (isLoop)
{
        if (cancelTokenSource.IsCancellationRequested)
        {
             isLoop = false;
        }
} 

以上问题即可解决

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值