如何等待取消的任务完成? [英] How to Wait for Canceled Task to Finish?

查看:21
本文介绍了如何等待取消的任务完成?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当谈到使用 .NET 4.0 进行并行编程时,我显然不知道自己在做什么.我有一个简单的 Windows 应用程序,它启动一项任务来做一些无意识的工作(输出数字 1-1000).我在中途暂停了一段时间来模拟一个长时间运行的过程.当这个长时间的停顿发生时,如果我点击停止按钮,它的事件处理程序会调用 CancellationTokenSource 的 Cancel 方法.我不想在停止按钮的事件处理程序中做任何进一步的处理(在这种情况下,输出消息),直到取消的任务完成当前迭代.我该怎么做呢?我尝试在停止按钮的事件处理程序中使用 Task.WaitAll 等,但这只会引发未处理的 AggregateException.如果按上述方式运行,以下代码将有助于解释我的问题:

I obviously don't know what I'm doing when it comes to parallel programming with .NET 4.0. I have a simple Windows app that starts a task to do some mindless work (outputting numbers 1-1000). I put a substantial pause in half way through to simulate a long running process. While this long pause is taking place, if I hit the Stop button, its event handler calls the Cancel method of CancellationTokenSource. I don't want to do any further processing (in this case, outputting a message) in the Stop button's event handler until the canceled task is done with its current iteration. How do I do this? I tried using Task.WaitAll, etc in the Stop button's event handler, but that just throws an unhandled AggregateException. Here's the code which will help explain my problem if run as described above:

  private Task t;
  private CancellationTokenSource cts;

  public Form1()
  {
     InitializeComponent();
  }

  private void startButton_Click(object sender, EventArgs e)
  {
     statusTextBox.Text = "Output started.";

     // Create the cancellation token source.
     cts = new CancellationTokenSource();

     // Create the cancellation token.
     CancellationToken ct = cts.Token;

     // Create & start worker task.
     t = Task.Factory.StartNew(() => DoWork(ct), ct);
  }

  private void DoWork(CancellationToken ct)
  {
     for (int i = 1; i <= 1000; i++)
     {
        ct.ThrowIfCancellationRequested();

        Thread.Sleep(10);  // Slow down for text box outout.
        outputTextBox.Invoke((Action)(() => outputTextBox.Text = i + Environment.NewLine));

        if (i == 500)
        {
           Thread.Sleep(5000);
        }
     }
  }

  private void stopButton_Click(object sender, EventArgs e)
  {
     cts.Cancel();

     Task.WaitAll(t);  // this doesn't work :-(

     statusTextBox.Text = "Output ended.";
  }

  private void exitButton_Click(object sender, EventArgs e)
  {
     this.Close();
  }

对此的任何帮助将不胜感激.提前致谢.

Any help with this would be greatly appreciated. Thanks in advance.

推荐答案

您通常只使用 Task.Wait(而不是 WaitAll),因为它是单个任务.然后适当地处理异常:

You would normally just use Task.Wait (instead of WaitAll), as it's a single task. and then handled the exception appropriately:

private void stopButton_Click(object sender, EventArgs e)
{
    cts.Cancel();
    try
    {
        t.Wait();  // This will throw
    }
    catch (AggregateException ae)
    {
       ae.Handle<OperationCanceledException>(ce => true);
    }

    statusTextBox.Text = "Output ended.";
}

当你取消一个 Task 时,OperationCanceledException 将被包装成一个 AggregateException 并在你调用 Wait 时被抛出() 或尝试获取 Task 的 Result(如果它是 Task).

When you cancel a Task, the OperationCanceledException will get wrapped into an AggregateException and be thrown as soon as you call Wait() or try to get the Task's Result (if it's a Task<T>).

仅供参考 - 这是一个地方,特别是考虑到您在这里所做的事情,C# 5 在这里简化了事情.使用新的异步支持,您可以将其编写为:

Purely for your information - This is one place, especially given what you're doing here, where C# 5 simplifies things. Using the new async support, you can write this as:

// No need for "t" variable anymore 
// private Task t;


private async void startButton_Click(object sender, EventArgs e)
{
   statusTextBox.Text = "Output started.";

   // Create the cancellation token source.
   cts = new CancellationTokenSource();

   try
   {
      // Create & start worker task.
      await Task.Run(() => DoWork(cts.Token));
      statusTextBox.Text = "Output ended.";
   }
   catch(OperationCanceledException ce) 
   {
      // Note that we get "normal" exception handling
      statusTextBox.Text = "Operation canceled.";
   }
}

private void stopButton_Click(object sender, EventArgs e)
{
   // Just cancel the source - nothing else required here
   cts.Cancel();
}

这篇关于如何等待取消的任务完成?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆