C# 取消任务并等待它完成

C# 取消任务并等待它完成,c#,task-parallel-library,C#,Task Parallel Library,我有一个耗时的任务,我需要在一个单独的线程中运行,以避免锁定GUI线程。随着此任务的进行,它将更新特定的GUI控件 问题是,在任务结束之前,用户可能会移动到GUI的另一部分,在这种情况下,我必须: 取消正在进行的任务(如果它处于活动状态) 等待完成取消:这是至关重要的,因为耗时任务的目标是更新特定控件。如果一次有多个线程尝试这样做,事情可能会变得一团糟 从头开始启动任务 对于一个具体的例子,假设表单有两个部分:一个是导航目录树的部分,另一个是显示缩略图的部分。当用户导航到另一个目录时,需要刷新缩

我有一个耗时的任务,我需要在一个单独的线程中运行,以避免锁定GUI线程。随着此任务的进行,它将更新特定的GUI控件

问题是,在任务结束之前,用户可能会移动到GUI的另一部分,在这种情况下,我必须:

  • 取消正在进行的任务(如果它处于活动状态)
  • 等待完成取消:这是至关重要的,因为耗时任务的目标是更新特定控件。如果一次有多个线程尝试这样做,事情可能会变得一团糟
  • 从头开始启动任务
  • 对于一个具体的例子,假设表单有两个部分:一个是导航目录树的部分,另一个是显示缩略图的部分。当用户导航到另一个目录时,需要刷新缩略图

    首先,我想用一个
    后台工作人员
    和一个
    自动恢复事件
    来等待取消,但我一定是弄糟了什么,因为取消时我陷入了僵局。然后我读了关于TPL的书,它应该取代BGW和更原始的机制

    使用第三方物流可以轻松做到这一点吗?

    需要注意的几点:

    • 您可以从
      CancellationTokenSource

    • 任务取消是一种合作的操作:如果您的任务没有定期检查
      CancellationToken.IsCancellationRequested
      属性,无论您尝试取消任务多少次,它都会愉快地消失

    这些话都说了,总的想法是:

    void Main()
    {
        var tokenSource = new CancellationTokenSource();
        var myTask = Task.Factory
            .StartNew(() => DoWork(tokenSource.Token), tokenSource.Token);
    
        Thread.Sleep(1000);
    
        // ok, let's cancel it (well, let's "request it be cancelled")
        tokenSource.Cancel();
    
        // wait for the task to "finish"
        myTask.Wait();
    }
    
    public void DoWork(CancellationToken token)
    {
        while(!token.IsCancellationRequested)
        {
            // Do useful stuff here
            Console.WriteLine("Working!");
            Thread.Sleep(100);
        }
    }
    

    只创建一次令牌源并每次将其令牌传递给
    StartNew
    可以吗?将其想象为一个孩子在字符串上的两个罐子(一到N个罐子:你有一个末端,所有开始的任务都有一个罐子。你喊“取消”一方面,所有共享令牌的人都会听到它。@dario_ramos我相信你评论中的问题在评论中得到了回答,但为了完整起见,答案是否定的-
    CancellationTokenSource
    不能再次重置和取消;如果你请求取消一个令牌,那么如果你想,你必须用一个新的替换它再次取消。@bohdan\u trotsenko该示例使用了一个称为synchronously的非异步方法。在同步方法中,正确的等待方式是
    Thread.Sleep
    。当心.Task.wait将抛出一个AggregateException,指示任务已取消(您已经知道,因为您已取消了它)。