如何取消正在运行的任务?

4

我想取消一个正在运行的任务(当用户按下“ESC”键时)。 当我点击“ESC”键时,Form_KeyDown会运行但不会取消任务!

CancellationTokenSource tokenSource = new CancellationTokenSource();
CancellationToken token=new CancellationToken();

private async void Search_Button_ClickAsync(object sender, EventArgs e)
{
  token = tokenSource.Token;
  await (Task.Factory.StartNew(() =>
           {
             //...my program
           },
           token));

private void Form_KeyDown(object sender, KeyEventArgs e)
{
  if (e.KeyCode == Keys.Escape)
  {
    tokenSource.Cancel();
  }
}

可能是如何中止/取消TPL任务?的重复问题。 - SᴇM
2
请帮我,这段代码不能运行!“不能运行”是什么意思? - mjwills
1个回答

9
除了需要停止方法内部代码的运行,你做得很好。通过将取消令牌传递给Task.Factory.StartNew,你不会中止任务。 让我引用 Stephen Toub 的话:
传递令牌到StartNew会将该令牌与任务相关联。这有两个主要好处:1)如果在任务开始执行之前已经请求取消,则任务将不会执行。它不会转换为Running状态,而是立即转换为Canceled状态。这可以避免在运行期间被取消时运行任务的成本。2)如果任务的主体也监视取消令牌并抛出包含该令牌的OperationCanceledException(就像ThrowIfCancellationRequested一样),那么当任务看到该OCE时,它会检查OCE的令牌是否与任务的令牌匹配。如果匹配,则视该异常为合作取消的确认,并将任务转换为Canceled状态(而不是Faulted状态)。
你需要手动检查你的令牌是否被取消并抛出操作取消异常,类似于以下内容:
 private async void Search_Button_ClickAsync(object sender, EventArgs e)
    {
      cToken = cTokenSource.Token;
      await (Task.Factory.StartNew(() =>
               {

               for(int i=0;i<yourtaskcount;i++)
               { 
                 cToken.ThrowIfCancellationRequested();

                  //long work
               cToken));
    }
    private void Form_KeyDown(object sender, KeyEventArgs e)
    {
      if (e.KeyCode == Keys.Escape)
      {
        tokenSource.Cancel();
      }
    }

1
谢谢亲爱的朋友,但我需要在点击“Escape”后立即取消。 - PEYMAN
@PEYMAN 这取决于你的业务逻辑是什么样子,以及你可以多久检查一次取消。你也可以中止任务,但这并不推荐。在这里查看:https://dev59.com/0G855IYBdhLWcg3waDeR 你也可以取消任务,并让它在后台一段时间后被取消。你的UI可以假装它已经被取消了,启用按钮/允许下一次运行开始。但你需要小心线程安全。 - MistyK
如果我使用ThrowIfCancellationRequested,那么任务会立即取消吗? - PEYMAN
1
@PEYMAN 是的,它确实可以,但它等同于先前的解决方案,只是更短。 - MistyK
@Default,您能否提供一下您的解决方案的示例程序代码? - PEYMAN

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接