我可以在取消任务之前处理CancellationTokenSource吗?

时间:2018-11-19 03:26:19

标签: c# parallel-processing task-parallel-library cancellation cancellationtokensource

我可以在取消CancellationTokenSource之前处置Task吗?如果没有,为什么?

代码1 (摘自Task Cancellation。为简化起见,我做了一些小的更改)似乎建议在处置Task之前先等待CancellationTokenSource。如果是这样,包含Dispose的类的CancellationTokenSource方法将比我希望的更加复杂。

在我的PC上,代码2 也似乎正常工作。我可以改用这种模式吗?

代码1:取消完成后处理

    [STAThread]
    private static void Main() {
        var tokenSource2 = new CancellationTokenSource();
        var task = DoAsync(tokenSource2.Token);
        tokenSource2.Cancel();
        tokenSource2 = null;

        try {
            task.Wait();
        }
        catch (AggregateException e) {
            foreach (var v in e.InnerExceptions)
                Console.WriteLine(e.Message + " " + v.Message);
        }
        finally {
            tokenSource2.Dispose();
        }

        Console.ReadKey();
    }

    private static async Task DoAsync(CancellationToken token) {
        while (true) {
            await Task.Delay(10000).ConfigureAwait(true);
            token.ThrowIfCancellationRequested();
        }
    }

代码2:取消之前先处理

    [STAThread]
    private static void Main() {
        var tokenSource2 = new CancellationTokenSource();
        var task = DoAsync(tokenSource2.Token);
        tokenSource2.Cancel();
        tokenSource2.Dispose();

        try {
            task.Wait();
        }
        catch (AggregateException e) {
            foreach (var v in e.InnerExceptions)
                Console.WriteLine(e.Message + " " + v.Message);
        }
        finally {
            //// tokenSource2.Dispose();
        }

        Console.ReadKey();
    }

    private static async Task DoAsync(CancellationToken token) {
        while (true) {
            await Task.Delay(10000).ConfigureAwait(true);
            token.ThrowIfCancellationRequested();
        }
    }

编辑:我的案子

实际上,我想知道是否必须通过Wait方法Dispose来取消任务。

    public class Class1 : IDisposable {
        //// tokenSource for calculationTask
        private CancellationTokenSource tokenSource;

        //// background calculation task
        private Task calculationTask;

        public void Dispose() {
            tokenSource?.Cancel();
            //// calculationTask.Wait(); Should I wait for task completion?
            tokenSource?.Dispose();
            tokenSource = null;

            calculationTask = null;
        }
    }

1 个答案:

答案 0 :(得分:1)

我不太了解您要做什么,但是让我们看一下事实。

处置令牌源不会影响令牌,但是,在任务完成之前处置令牌是没有意义的。另外,如果可用,请始终使用using语句。

此外,您可以在C#7.1或更高版本中使用异步主要方法。只需在构建设置中更改高级选项即可。

我认为这似乎是您更常用的方式

// use async all the way down
static async Task Main(string[] args)
{
   // using using using
   using (var tokenSource2 = new CancellationTokenSource())
   {
      try
      { 
         var task = DoAsync(tokenSource2.Token);

         // test cancel
         tokenSource2.Cancel();

         // await anything you need.
         await Task.WhenAll(task);  
      }
      // catch CanceledException
      catch (OperationCanceledException)
      {
         Console.WriteLine("Canceled");
      }
      // notice we get normal exceptions and not aggregates 
      catch (Exception e)
      {
         Console.WriteLine(e.Message);
      }    
   }   
   Console.ReadKey();
}

private static async Task DoAsync(CancellationToken token)
{
   // pass your toke in to anything that needs it
   await Task.Delay(10000,token).ConfigureAwait(true);
   token.ThrowIfCancellationRequested(); 
}