Serbin
Serbin

Reputation: 823

Cancel all async tasks

Is it possible to cancel all async methods, without knowing what is currently running?

For example I have several classes that may run async tasks:

class Class1
{
    public async void SomeTask()
    {
        for (int i = 0; i < 5; i++)
        {
            // Doing some job
            await Task.Delay(2000);
        }
    }
}

class Class2
{
    public async void ContinuouslyTask()
    {
        for (;;)
        {
            // Doing some job on background
            await Task.Delay(1000);
        }
    }
}

And I want turn off every async task, before I will logout:

class Program
{
    static void Main(string[] args)
    {
        var p = new Program();
        var c1 = new Class1();
        var c2 = new Class2();

        c1.SomeTask();
        c2.ContinuouslyTask(); 

        while (Console.ReadKey().Key != ConsoleKey.Enter) { }

        p.Logout();
    }

    private void Logout()
    {
        // Cancel all async tasks

        // And do logout work
    }
}

Is it possible to do this, without saving tasks into query?

Upvotes: 7

Views: 7821

Answers (2)

Yuval Itzchakov
Yuval Itzchakov

Reputation: 149618

This is basically extending @FrankFajardo answer to provide a concrete example. When you pass in a CancellationToken, you also need to monitor it for any cancellation request from the outside. It will look like this:

class Class1
{
    public async Task SomeTaskAsync(CancellationToken cancellationToken)
    {
        for (int i = 0; i < 5; i++)
        {
            if (cancellationToken.IsCancellationRequested)
                break;
            // Doing some job
            await Task.Delay(2000);
        }
    }
}

class Class2
{
    public async Task ContinuouslyTaskAsync(CancellationToken cancellationToken)
    {
        while (!cancellationToken.IsCancellationRequested)
        {
            // Doing some job on background
            await Task.Delay(1000);
        }
    }
}

And now when you want to cancel it, you simply add CancellationTokenSource.Cancel() call to your code:

static void Main(string[] args)
{
    var p = new Program();
    var c1 = new Class1();
    var c2 = new Class2();

    var cancellationTokenSource = new CancellationTokenSource();
    var someTask = c1.SomeTask(cancellationTokenSource.Token);
    var continuousTask = c2.ContinuouslyTask(cancellationTokenSource.Token); 

    while (Console.ReadKey().Key != ConsoleKey.Enter) { }

    cancellationTokenSource.Cancel();
    Task.WaitAll(someTask, continuousTask);

    p.Logout();
}

Note I'm using Task.WaitAll only because this is a console application where Main can't be async. Otherwise, use Task.WhenAll which returns an awaitable Task.

Upvotes: 4

Frank Fajardo
Frank Fajardo

Reputation: 7359

You should look at CancellationTokenSource.

You should make your c1.SomeTask() and c2.ContinuouslyTask() accept cancellation tokens, and check for that token to see if the reques is being cancelled, and end abruptly if so.

Then in your Program.Main(), it should create a CancellationTokenSource and pass the CancellationTokenSource.Token to the 2 async method it calls. This CancellationTokenSource should be accessible to the Program.Logout() so that it can issue the cancellation on logout. See example here

NOTE: It is generally advised that async methods return Tasks, instead of void. Also, it is a convention that async methods are named xxxAsync (eg. DoWorkAsync).

Upvotes: 3

Related Questions