Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a cancellable task loop?

Is it possible to use System.Threading.Task.Task to create a loop of task that can be cancelled?

The flow should start with a Task.Delay(x ms) then continue with userdefined task, then another Task.Delay(y ms) and repeat from the user defined task.

var result = Task.Delay(initialDelay)
              .ContinueWith(t => dostuff..)
              .ContinueWith what goes here?

Is it even doable using tasks?

I could spin up a timer and be done with it, but using task seems to be the right way to go if I need cancellation, no?

like image 903
Roger Johansson Avatar asked Feb 26 '14 17:02

Roger Johansson


People also ask

How do I cancel async tasks?

You can cancel an asynchronous operation after a period of time by using the CancellationTokenSource. CancelAfter method if you don't want to wait for the operation to finish.

Which of the following option should be used to implement cancellation for a long running task?

In this article, we will learn How to cancel or interrupt the Long Running Task using a Cancellationtokensource method in . NET 4.0. In this article, we are going to learn how to cancel or interrupt the Long Running Task using the Cancellationtokensource method in .

What is CancellationToken C# task?

If you want to signal to outside users that your task has been cancelled. You can do this by throwing an OperationCancelledException. CancellationTokenSource tokenSource = new CancellationTokenSource(); CancellationToken token = tokenSource.Token; Task t1 = Task.Factory.StartNew(() =>


1 Answers

await makes this super easy:

public async Task TimedLoop(Action action, 
    CancellationToken token, TimeSpan delay)
{
    while (true)
    {
        token.ThrowIfCancellationRequested();
        action();
        await Task.Delay(delay, token);
    }
}

Without async (but still just using the TPL) it's a bit messier. I generally solve this problem by having a continuation that attaches itself to a variable of type Task. This works fine, but it can take a second to wrap your head around it. Without await it may be easier to just use a Timer instead.

public Task TimedLoop(Action action,
    CancellationToken token, TimeSpan delay)
{
    //You can omit these two lines if you want the method to be void.
    var tcs = new TaskCompletionSource<bool>();
    token.Register(() => tcs.SetCanceled());

    Task previous = Task.FromResult(true);
    Action<Task> continuation = null;
    continuation = t =>
    {
        previous = previous.ContinueWith(t2 => action(), token)
            .ContinueWith(t2 => Task.Delay(delay, token), token)
            .Unwrap()
            .ContinueWith(t2 => previous.ContinueWith(continuation, token));
    };
    previous.ContinueWith(continuation, token);
    return tcs.Task;
}
like image 177
Servy Avatar answered Oct 01 '22 00:10

Servy