检查CancellationToken是否已取消

时间:2019-10-08 11:34:28

标签: c# asynchronous cancellationtokensource

我创建了一个演示项目,以帮助我了解如何使用取消令牌。我了解您已取消令牌并检查是否已请求取消,但是有什么方法可以检查是否已实现取消?在下面的示例中,我不想在DoWork()完成运行之前再次运行Work()。

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 个答案:

答案 0 :(得分:2)

您通常不希望将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”。如果没有,则可以将Main方法编写为:

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

答案 1 :(得分:1)

如果所有操作都是异步的并且可以取消的,那么您将充分利用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