Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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. As this task progresses, it updates a specific GUI control.

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:

  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. Then I read about TPL, which is supposed to replace BGW and more primitive mechanisms.

Can this be done easily using TPL?

like image 763
dario_ramos Avatar asked Feb 14 '13 19:02

dario_ramos


People also ask

What is task Cancelled exception?

It works fine when have one or two tasks however throws an error "A task was cancelled" when we have more than one task listed. List<Task> allTasks = new List<Task>(); allTasks.Add(....

What is difference between CancellationTokenSource and CancellationToken?

CancellationTokenSource – an object responsible for creating a cancellation token and sending a cancellation request to all copies of that token. CancellationToken – a structure used by listeners to monitor token current state.

What is a CancellationToken?

A CancellationToken enables cooperative cancellation between threads, thread pool work items, or Task objects. You create a cancellation token by instantiating a CancellationTokenSource object, which manages cancellation tokens retrieved from its CancellationTokenSource.


1 Answers

A few things to note:

  • You can get a CancellationToken from a CancellationTokenSource

  • 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.

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);
    }
}
like image 123
JerKimball Avatar answered Oct 03 '22 17:10

JerKimball