如何等待取消的任务完成?

Mac*_*Mac 23 .net parallel-processing c#-4.0

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

  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();
  }
Run Code Online (Sandbox Code Playgroud)

任何有关这方面的帮助将不胜感激.提前致谢.

Ree*_*sey 10

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

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.";
}
Run Code Online (Sandbox Code Playgroud)

当你取消a时Task,一旦你打电话或试图获得任务(如果它是a ),OperationCanceledException它将被包裹成一个AggregateException并被抛出.Wait()ResultTask<T>


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

// 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();
}
Run Code Online (Sandbox Code Playgroud)

  • 我没有看到**AggregateException.Handle <T>**的通用形式.这是你写的扩展方法吗? (4认同)