取消任务并等待它完成

dar*_*mos 12 c# task-parallel-library

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

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

  1. 取消正在进行的任务(如果它处于活动状态)
  2. 等到它完成取消:这是至关重要的,因为耗时任务的目标是更新特定控件.如果多个线程同时尝试执行此操作,事情可能会变得混乱.
  3. 从头开始执行任务

举一个具体的例子,假设表单有两个部分:一个用于导航目录树,另一个用于显示缩略图.当用户导航到另一个目录时,需要刷新缩略图.

首先我想用a BackgroundWorker和a AutoResetEvent等待取消,但我必须弄乱一些东西,因为我在取消时遇到了僵局.然后我读到了TPL,它应该取代BGW和更原始的机制.

使用TPL可以轻松完成吗?

Jer*_*all 24

有几点需要注意:

  • 你可以CancellationToken从一个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);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 谨防。Task.Wait 将抛出 AggregateException ,指示任务已取消(您已经知道,因为您取消了它)。https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.wait?view=netframework-4.8#System_Threading_Tasks_Task_Wait_System_TimeSpan_ (2认同)