【问题标题】:Can I dispose CancellationTokenSource before Task be cancelled?我可以在任务被取消之前处理 CancellationTokenSource 吗?
【发布时间】:2018-11-19 03:26:18
【问题描述】:

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

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

在我的电脑上,代码 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();
        }
    }

编辑:我的情况

其实我想知道是否必须在Dispose 方法中使用Wait 来取消任务。

    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;
        }
    }

【问题讨论】:

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


    【解决方案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(); 
    }
    

    【讨论】:

    • 感谢@TheGeneral 的回答!我的问题可能模棱两可。实际上我想知道我是否应该在Wait 方法中以Dispose 方法取消任务。请检查已编辑的部分。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-10-24
    • 1970-01-01
    • 2012-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多