How to safely cancel a task using a CancellationToken and await Task.WhenAll

前端 未结 2 1644
时光说笑
时光说笑 2021-01-25 07:18

I have a framework which creates a CancellationTokenSource, configures CancelAfter, then calls an async method and passes the Token. The async method then spawns many tasks, pas

相关标签:
2条回答
  • 2021-01-25 08:00

    Provide the CancellationToken to Task.Run in addition to passing it to the method doing the work. When you do this Task.Run can see that the exception thrown was caused by the CancellationToken it was given, and will mark the Task as cancelled.

    tasks.Add(Task.Run(() => this.DoWork(work, cancelationToken),
        cancelationToken));
    

    Once you've done this you can ensure that DoWork throws when the token is cancelled, rather than checking IsCancellationRequested to try to end by being marked as "completed successfully".

    0 讨论(0)
  • 2021-01-25 08:21

    I recommend that you follow the standard cancellation pattern of throwing an exception rather than just returning:

    public static void DoWork(work, cancellationToken)
    {
      while (work.IsWorking)
      {
        cancellationToken.ThrowIfCancellationRequested();
        work.DoNextWork();
      }
    }
    

    If you have cleanup work to do, that's what finally is for (or using, if you can refactor that way):

    public async Task Run(CancellationToken cancellationToken)
    {
      HashSet<Task> tasks = new HashSet<Task>();
      foreach (var work in this.GetWorkNotPictured)
      {
        tasks.Add(Task.Run(() => this.DoWork(work, cancellationToken))
      }
    
      try
      {
        await Task.WhenAll(tasks);
      }
      finally
      {
        this.CleanUpAfterWork();
      }
    }
    
    0 讨论(0)
提交回复
热议问题