c# - 取消 CancellationToken 是否会导致 CancellationToken 异常?

标签 c# multithreading cancellation-token

我有这段代码,我想得到一些有关 CancellationToken 的使用的说明。

我读到了这个关于使用取消 token 和标志之间的区别的问题:

Difference between CancellationTokenSource and exit flag for Task loop exit

我注意到的一件事是它没有提到任何有关异常的内容。这是我的问题。 如果调用 Disappearing() 方法,那么这是否会导致 TaskCanceledException() 发生,这是否是使用 CancellationToken 而不是标志的好理由?

public partial class PhrasesFrame : Frame
{
    CancellationTokenSource cts = new CancellationTokenSource();

    public PhrasesFrame(PhrasesPage phrasesPage)
    {
        Device.BeginInvokeOnMainThread(() => ShowCards(cts.Token).ContinueWith((arg) => { }));
    }

    public void Disappearing()
    {
        cts.Cancel();
    }

    public async Task ShowCards(CancellationToken ct)
    {
        while (!ct.IsCancellationRequested)
        {
            await PickCard();
        }
    }

    public async Task PickCard()
    {
        await ShowCard();
    }

    private async Task ShowCard()
    {
        await ShowPhrase();
        await ShowDetail();
    }

    private async Task ShowPhrase()
    {
        while (App.pauseCard || timer1Seconds > 0)
        {
            try
            {
                await Task.Delay(1000, tokenSource1.Token);
            }
            catch (TaskCanceledException)
            {
                // do action
                break;
            }
        }

最佳答案

CancellationTokenSource.Cancel 本身不会引发此类异常,但它将所有相关取消 token “移动”到已取消状态。当某些代码通知取消 token 现在处于取消状态时 - 它可能抛出此类异常。如果看你的例子,这部分不会抛出这样的异常:

public async Task ShowCards(CancellationToken ct)
{
    while (!ct.IsCancellationRequested)
    {
        await PickCard();
    }
}

因为你只是不把它扔到这个 block 中。然而,如果你做了这样的事情:

public async Task ShowCards(CancellationToken ct)
{
    while (true)
    {
        ct.ThrowIfCancellationRequested();
        await PickCard();
    }
}

然后就会抛出异常,因为,你几乎明确地抛出了它。

现在,如果看一下示例中的另一种方法:

private async Task ShowPhrase()
{
    while (App.pauseCard || timer1Seconds > 0)
    {
        try
        {
            await Task.Delay(1000, tokenSource1.Token);
        }
        catch (TaskCanceledException)
        {
            // do action
            break;
        }
    }
}

如果您正在等待 Task.Delay(1000, tokenSource1.Token);,然后取消 tokenSource1 - 那么 TaskCancelledException 确实会被抛出立即执行,无需等待 Task.Delay 的整个持续时间。这是仅使用 bool 标志无法轻松实现的目标。如果您使用了 Thread.Sleep(1000) 和 bool 标志 - 在整个 sleep 期间完成之前,不会注意到对该标志的更改。

因此,回答您的问题:在您的示例中,可能会或可能不会引发异常,具体取决于您取消 CancellationTokenSource 时当前正在执行的代码部分(我假设使用两个取消名为 ctstokenSource1 的 token 源只是代码中的拼写错误,但如果它是真实代码 - 那么根本不能抛出此类异常,因为您取消了 ctsTask.Delay 等待 tokenSource1)。

关于c# - 取消 CancellationToken 是否会导致 CancellationToken 异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47967118/

相关文章:

c# - 任务构造函数中的取消标记 : why?

c# - 使用 LINQ 获取多维数组的分区(N 维数组的 (N-1) 维实例)

c# - Microsoft JScript 运行时错误 : 'Sys' is undefined (in mvc3 c# razor)

c# - Windows 7 开始菜单搜索的自定义源

c# - 如何在 LINQ to Entities (Entity Framewok) 中编写 SQL ORDER BY {value} DESC LIMIT 语句?

c# - 如何从 Windows 服务运行 exe 并在 exe 进程退出时停止服务?

c++ - 创建互斥问题

java - Thread.sleep(long mills) 也延迟了以前的方法

c# - 我是否应该始终将 CancellationToken 添加到我的 Controller 操作中?

c# - 如何保证 CancellationTokens 是最新的?