Проверьте, отменен ли CancellationToken - PullRequest
0 голосов
/ 08 октября 2019

Я создал небольшой демонстрационный проект, чтобы помочь мне понять, как я могу использовать токены отмены. Я понимаю, что вы отменяете токен и проверяете, было ли запрошено аннулирование, но есть ли способ проверить, была ли аннулирована аннулирование? В моем примере ниже я не хочу снова запускать Work () до тех пор, пока DoWork () не завершит работу.

public class Program
{
    public static CancellationTokenSource tokenSource;

    private static void Main(string[] args)
    {
        while (true)
        {
            Work();
        }
    }

    public static async void Work()
    {
        tokenSource = new CancellationTokenSource();
        Console.WriteLine("Press any key to START doing work");
        Console.ReadLine();
        Console.WriteLine("Press any key to STOP doing work");
        DoWork(tokenSource.Token);
        Console.ReadLine();
        Console.WriteLine("Stopping...");
        tokenSource.Cancel();
    }

    public static async void DoWork(CancellationToken cancelToken)
    {
        while (true)
        {
            Console.WriteLine("Working...");
            await Task.Run(() =>
            {
                Thread.Sleep(1500);
            });

            if (cancelToken.IsCancellationRequested)
            {
                Console.WriteLine("Work Cancelled!");

                return;
            }
        }
    }
}

Ответы [ 2 ]

2 голосов
/ 08 октября 2019

Как правило, вы не хотите, чтобы ваша DoWork функция async void - вместо этого установите async Task. Таким образом, вы можете увидеть, когда он будет завершен (или отменен).

Возможно, вы также захотите использовать cancelToken.ThrowIfCancellationRequested(). Это выдает OperationCanceledException, который вы можете поймать.

public class Program
{
    public static CancellationTokenSource tokenSource;

    private static async Task Main(string[] args)
    {
        while (true)
        {
            await Work();
        }
    }

    public static async Task Work()
    {
        tokenSource = new CancellationTokenSource();
        Console.WriteLine("Press any key to START doing work");
        Console.ReadLine();
        Console.WriteLine("Press any key to STOP doing work");

        var task = DoWork(tokenSource.Token);

        Console.ReadLine();
        Console.WriteLine("Stopping...");
        tokenSource.Cancel();

        try
        {
            await task;
        }
        catch (OperationCanceledException)
        {
            // Task was cancelled
        }
    }

    public static async Task DoWork(CancellationToken cancelToken)
    {
        while (true)
        {
            Console.WriteLine("Working...");
            await Task.Run(() =>
            {
                Thread.Sleep(1500);
            });

            cancelToken.ThrowIfCancellationRequested();
        }
    }
}

Этот код опирается на "асинхронную основную", которая была введена в C # 7. Если у вас ее нет, вы можете написать свой Mainметод как:

private static void Main(string[] args)
{
    while (true)
    {
        Work().Wait();
    }
}
1 голос
/ 08 октября 2019

Вы получите максимум от CancellationToken, если все ваши операции будут асинхронными и отменяемыми. Таким образом, отмена токена будет иметь немедленный эффект. Вам не нужно ждать завершения Thread.Sleep или другого блокирующего вызова.

public static async Task DoWork(CancellationToken cancellationToken)
{
    while (true)
    {
        await Console.Out.WriteLineAsync("Working...");
        await Task.Delay(1500, cancellationToken);
    }
}

В этом примере токен передается только на Task.Delay, потому что WriteLineAsync не может быть отменено в .NET Framework (это в .NET Core).

OperationCanceledException будет повышено на Task.Delay при отмене токена.

...