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

标签 .net c#-4.0 parallel-processing

当谈到使用 .NET 4.0 进行并行编程时,我显然不知道自己在做什么。我有一个简单的 Windows 应用程序,它启动一个任务来执行一些无需动脑子的工作(输出数字 1-1000)。我在中途暂停了一段时间来模拟一个长时间运行的过程。当发生长时间暂停时,如果我点击“停止”按钮,其事件处理程序将调用 CancellationTokenSource 的 Cancel 方法。我不想在“停止”按钮的事件处理程序中进行任何进一步的处理(在本例中为输出消息),直到取消的任务完成其当前迭​​代。我该怎么做呢?我尝试在“停止”按钮的事件处理程序中使用 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();
  }

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

最佳答案

您通常只需使用 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.";
}

当您取消Task时,OperationCanceledException将被包裹成 AggregateException一打电话Wait()就被扔了或尝试获取任务的 Result (如果是 Task<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();
}

关于.net - 如何等待取消的任务完成?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11997166/

相关文章:

c# - 通过远程桌面连接时出现 IValueConverter NullReferenceException

c#-4.0 - Windows Azure 模拟器 "Invalid access to memory location."

linux - 守护进程 MCE 进程的状态影响父进程

android - Q : How to run single test in multiple devices?

.net - 如何使用 Dapr 订阅 Azure 应用程序配置中的更改

c# - VS2015 C# interactive : error CS7069: Reference to type 'Object' claims it is defined in 'System.Runtime' , 但找不到

c# - 寻找应用路径

c# - 循环数据集的每一行和相同的数据集列表形式之间会有任何性能差异吗

c# - C# 中的 Directory.GetFiles() 模式匹配

r - listcolumns 和 multidplyr