简体   繁体   English

取消任务并等待它完成

[英]Cancel task and wait for it to finish

I have a time consuming task which I need to run in a separate thread to avoid locking the GUI thread. 我有一个耗时的任务,我需要在一个单独的线程中运行,以避免锁定GUI线程。 As this task progresses, it updates a specific GUI control. 随着此任务的进行,它会更新特定的GUI控件。

The catch is that the user might move to another part of the GUI before the task is over, and in that case, I have to: 问题是用户可能在任务结束之前移动到GUI的另一部分,在这种情况下,我必须:

  1. Cancel the ongoing task (if it is active) 取消正在进行的任务(如果它处于活动状态)
  2. Wait till it's done cancelling: this is crucial, because the time consuming task's objective is to update a specific control. 等到它完成取消:这是至关重要的,因为耗时任务的目标是更新特定控件。 If more than one thread tries to do it at once, things might get messy. 如果多个线程同时尝试执行此操作,事情可能会变得混乱。
  3. Launch the task from scratch 从头开始执行任务

For a concrete example, imagine the form has two parts: one where you navigate a directory tree, and another where you display thumbnails. 举一个具体的例子,假设表单有两个部分:一个用于导航目录树,另一个用于显示缩略图。 When the user navigates to another directory, thumbnails need to be refreshed. 当用户导航到另一个目录时,需要刷新缩略图。

First I thought of using a BackgroundWorker and an AutoResetEvent to wait for cancellation, but I must have messed something because I got deadlocked when cancelling. 首先我想到使用BackgroundWorkerAutoResetEvent等待取消,但我必须弄乱一些东西,因为我在取消时遇到了死锁。 Then I read about TPL, which is supposed to replace BGW and more primitive mechanisms. 然后我读到了关于TPL,它应该取代BGW和更原始的机制。

Can this be done easily using TPL? 使用TPL可以轻松完成吗?

A few things to note: 有几点需要注意:

  • You can get a CancellationToken from a CancellationTokenSource 你可以得到CancellationTokenCancellationTokenSource

  • Task cancellation is a cooperative action: if your task does not periodically check the CancellationToken.IsCancellationRequested property, it doesn't matter how many times you try to cancel the task, it will merrily churn away. 任务取消是一种合作行为:如果您的任务没有定期检查CancellationToken.IsCancellationRequested属性,那么尝试取消任务的次数并不重要,它会随意地流失。

Those things said, here's the general idea: 那些事情说,这是一般的想法:

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);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM