如何正确取消Task并捕获OperationCanceledException?

时间:2019-02-15 23:07:30

标签: c# .net task

这个问题已经被问到了,但我还是不明白...我试图取消一个任务,但是当我包含ThrowIfCancellationRequested()时,它不会被捕获,如果我不包含它, GUI冻结...

这是我的代码,没有ThrowIfCancellationRequested()运行但冻结了GUI:

 public void StartProcess(double myvariable)
    {
        tokenSource = new CancellationTokenSource();
        CancellationToken token = tokenSource.Token;

        processThread = Task.Factory.StartNew(() =>
        {
            while (true)
            {
                //Do some work with myvariable

                if (token.IsCancellationRequested)
                {
                    break;
                }
            }
        }, token);
    }

并且未捕获到带有ThrowIfCancellationRequested()的代码,调试器将在行令牌上停止。ThrowIfCancellationRequested():

 public void StartProcess(double myvariable)
    {
        tokenSource = new CancellationTokenSource();
        CancellationToken tokenDispatcher = tokenSource.Token;

        processThread = Task.Factory.StartNew(() =>
        {
            try
            {
                while (true)
                {
                    //Do some work with myvariable

                    if (token.IsCancellationRequested)
                    {
                        token.ThrowIfCancellationRequested();
                        break;
                    }
                }
            }
            catch (AggregateException ae)
            {
                    if (ae.InnerException is OperationCanceledException)
                    {
                        Console.WriteLine("Process Thread Cancelled");
                    }
                    else
                    {
                        Console.WriteLine("ERROR");
                    }
            }
        }, token);
    }

我在做什么错了?

1 个答案:

答案 0 :(得分:1)

ThrowIfCancellationRequested是取消任务的正确方法。您需要了解的是,取消任务时不会有例外。仅任务的Status将被设置为Canceled。您在任务中拥有的try catch块将无济于事。 要获取异常,您需要以异步方法等待Task或使用Wait方法等待任务完成。不建议使用Wait方法,因为您将阻塞当前线程,直到任务完成。

以下是您如何从代码中实现此建议。

public static Task StartProcess(double myvariable)
{
   tokenSource = new CancellationTokenSource();
   CancellationToken token = tokenSource.Token;

   return Task.Factory.StartNew(() =>
   {
      while (true)
      {
         //Do some work with myvariable

         token.ThrowIfCancellationRequested();
      }
   }, token);
}

public async Task ExecuteProcess(double myvariable)
{
   try
   {
      await StartProcess(myvariable);
   }
   catch (OperationCanceledException ex)
   {
      Console.WriteLine("Process Thread Canceled");
   }
   catch (Exception ex)
   {
      Console.WriteLine("ERROR");
   }
}

ExecuteProcess方法演示了如何调用函数以获取异常。这样,如果您从UI线程调用方法,也可以防止GUI阻塞。

我建议您阅读documentation on asynchronous programming,以进一步了解其工作原理。