Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 955
Serbin Avatar asked Jan 16 '16 12:01

Serbin


2 Answers

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.

like image 109
Yuval Itzchakov Avatar answered Sep 28 '22 16:09

Yuval Itzchakov


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

like image 20
Frank Fajardo Avatar answered Sep 28 '22 15:09

Frank Fajardo