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

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

问题描述

我显然不知道我在做什么,当涉及到并行编程.NET 4.0。我有一个简单的Windows应用程序,启动一个任务,做一些不用动脑筋的工作(输出编号1-1000)。我把大量的停顿一半的方式,通过模拟一个长期运行的进程。虽然这种长时间的停顿正在发生,如果我打了停止按钮,它的事件处理程序调用CancellationTokenSource的取消方法。我不希望做任何进一步的处理(在这种情况下,输出一个消息)中的停止按钮的事件处理程序,直到取消任务与它的当前迭代完成。我该怎么做呢?我尝试使用Task.WaitAll等在停止按钮的事件处理,但只是抛出一个未处理AggregateException。这里的code,这将有助于如果运行解释我的问题上面所描述的:

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

任何帮助,这将大大AP preciated。先谢谢了。

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

当您取消工作 OperationCanceledException 将获得缠成 AggregateException ,并尽快为你调用等待()抛出或试图获得任务的结果 (如果它是一个任务&LT; T&GT; )。

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天全站免登陆