你的位置:首页 > ASP.net教程

[ASP.net教程]Task:取消异步计算限制操作 捕获任务中的异常


Why:ThreadPool没有内建机制标记当前线程在什么时候完成,也没有机制在操作完成时获得返回值,因而推出了Task,更精确的管理异步线程。

How:通过构造方法的参数TaskCreationOptions控制如何创建任务,具体查看该枚举的枚举值。获取任务执行的结果有Task.Result属性,该属性内部调用wait(),例如WaitAny()、WaitAll()等等都可以。

如何取消异步计算限制操作呢?也就是说如何取消执行中的任务呢?(鄙视clr的作者用“计算限制操作”这么复杂的词汇。)

实例化CancelletionTokenSource类,把该对象作为参数传给异步方法,在异步方法中调用该对象的ThrowIfCancellationRequested(),如果该对象的Cancel()方法被调用了,那么异步方法就会抛出异常OperationCanceledException,在主线程用try-catch进行捕获(AggregateException),就可以捕获异常并进行处理。

 class Program  {    static void Main(string[] args)    {      CancellationTokenSource cts = new CancellationTokenSource();//CancellationTokenSource(3000);//3秒后没有得到结果,则取消该线程。      Task<Int32> t1 = Task.Run(() => sum(cts.Token, 10000), cts.Token);//传入CancellationToken,它是CancellationTokenSource的属性。      cts.Cancel();//cts.CancelAfter(3000);//3秒后如果没有得到结果,则取消该线程。      try      {        Console.WriteLine("t1执行的结果是:" + t1.Result);//通过Result获取t1的执行结果。      }      catch (AggregateException ex)      {        ex.Handle(e => e is OperationCanceledException);        Console.WriteLine("sum已经被取消");      }      Console.ReadKey();    }    private static int sum(CancellationToken ct, int p)    {      int sum = 0;      while (p > 0)      {        ct.ThrowIfCancellationRequested();        Thread.Sleep(500);//每隔半秒累加一次。        checked//如果区域内的计算溢出就会抛出异常        {          sum += p;        }        p--;      }      return sum;    }}

 

运行结果:sum已经被取消

成功的捕获到了异常并处理了。

但是我发现有一个地方我不能理解

1、如果是通过CancellationTokenSource的构造方法public CancellationTokenSource(int millisecondsDelay);构造的实例对象,try-catch捕获不到异常。

2、如果是通过CanelAfter(TimeSpan delay)取消,也捕获不到异常。

通过ILSpy我发现上诉构造方法和CanelAfter方法都是调用Cancel()方法,但是为何捕获不到异常呢?

我进一步查看ThrowIfCancellationRequested源码

public void ThrowIfCancellationRequested()    {      if (this.IsCancellationRequested)      {        this.ThrowOperationCanceledException();      }    }

但是Cancel()方法的源码中并没有修改this.IsCancellationRequested属性,百思不得解,求大神指点。