Dave New
Dave New

Reputation: 40012

Cancel an executing Task in a task queue

I have a list of items which I need to process sequentially (but on a separate worker thread so to maintain UI responsiveness). The important thing to note is that these items can run for a long time (5 - 10 seconds).

Task<bool> currentTask = null;

foreach (var item in items)
{
    var currentItem = item;

    // Add a new task to the sequential task queue
    if (currentTask == null)
        currentTask = Task.Factory.StartNew<bool>(() => 
        { 
            return currentItem.ProcessItem(); 
        }, processCancelTokenSource.Token);
    else
        currentTask = currentTask.ContinueWith<bool>(t => 
        { 
            return currentItem.ProcessItem(); 
        }, processCancelTokenSource.Token);

    // Update UI after each task completes
    currentTask.ContinueWith(t =>
    {
        if (t.IsCanceled)
            currentItem.State = State.Cancelled;
        else
        {
            if (t.Result)
                currentItem.State = State.Complete;
            else
                currentItem.State = State.Failed;
        }
    },TaskScheduler.FromCurrentSynchronizationContext());
}

Now, I am using a CancellationToken to cancel the processing of the queue (there is a "Cancel Processing" button).

The problem is that this does not cancel the Task which is currently being executed. If CancellationTokenSource.Cancel() is called, then all the tasks waiting to be executed in the queue will be cancelled and their item's currentItem.State will be set to State.Cancelled, which is correct. The problem is that the task which was executing at the time of the cancellation will continue to execute until it is finished and then be set to State.Complete or State.Failed. This is not ideal for two reasons: (1) the task is still running after the cancellation, (2) the state is not set to State.Cancelled because t.IsCanceled is not true.

Is there a way for me to safely cancel/stop the currently executing Task?

Upvotes: 1

Views: 3293

Answers (2)

Dennis
Dennis

Reputation: 37770

Tasks supports graceful cancellation pattern. CancellationToken is just a token. It doesn't interrupt any executing code or aborting a thread. You should check this token in task body yourself.

One point to remember: if you want to get your current task cancelled, cancel it via CancellationToken.ThrowIfCancellationRequested method, not just exiting from task body.

Upvotes: 5

margabit
margabit

Reputation: 2954

Check this msdn article about Task Cancellation. http://msdn.microsoft.com/en-us/library/dd997396.aspx All you have to do is check if the Task is cancelled inside the Task's working method. Place your check cancellation code in the critical areas of the method. Hope it helps!

Upvotes: 3

Related Questions