Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stop a Task without ThrowIfCancellationRequested

I have a task which i want to cancel.

The normal method for doing this is with CancellationToken.

this.task = new SpecialTask(() =>
{
    for (int i = 0; i < ushort.MaxValue; i++)
    {
        CancelToken.ThrowIfCancellationRequested();
        Console.WriteLine(i);
    }
}, this.CancelToken);

However, in real world things are never that simple. Our async code cannot be looped and it looks like this:

this.task = new SpecialTask(() =>
{
    CancelToken.ThrowIfCancellationRequested();
    Operation1();

    CancelToken.ThrowIfCancellationRequested();
    Operation267(CancelToken);

    CancelToken.ThrowIfCancellationRequested();
    object232.Operation345();

    CancelToken.ThrowIfCancellationRequested();
    object99.Operation44(CancelToken);

    CancelToken.ThrowIfCancellationRequested();
    Operation5(CancelToken);

    ...

    CancelToken.ThrowIfCancellationRequested();
    Operation...n(CancelToken);

}, this.CancelToken);

I used random numbers for objects and method names to show that no loop can be created whatsoever.

What is most bothering is that I have to keep writing the same CancelToken.ThrowIfCancellationRequested() over and over again.

And, as if that's not enough, I have to drag the CancellationToken all over my code just to be able to stop the long running operation - according to Microsoft - at the right time.

Having said that, is there a way I can dispense of these repetitive calls which poison my code?

We also know that, when using

try
{
    task.Wait(cancelToken);
}
catch(OperationCancelledException)
{
}

an OperationCancelledException is thrown and caught for the Wait method. However, the long operation executed by the task doesn't stop if there are no CancelToken.ThrowIfCancellationRequested() checks from time to time.

Is there any way possible to make the inside operation stop when the exception is caught for the wait?

like image 515
Paul Avatar asked Nov 03 '22 19:11

Paul


1 Answers

You can refactor your code into a loop to avoid the repetitive cancellation between each line:

var actions = new List<Action>()
{
    ()=>Operation1(),
    ()=>Operation267(CancelToken),
    ()=>object232.Operation345(),
    //...
};

foreach (var action in actions)
{
    action();
    CancelToken.ThrowIfCancellationRequested();
}
like image 159
Servy Avatar answered Nov 15 '22 05:11

Servy