取消CancellationToken会导致CancellationToken异常吗?

时间:2017-12-25 08:52:03

标签: c# multithreading cancellation-token

我有这段代码,我想对CancellationToken的使用做一些澄清。

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

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;
            }
        }

1 个答案:

答案 0 :(得分:1)

historyApiFallback: { index: '/' }, 本身并没有抛出这样的异常,但它会移动"所有相关的取消令牌到取消状态。当某些代码通知取消令牌现在处于取消状态时 - 可能抛出此类异常。如果看一下你的例子,这部分就不会抛出这样的异常:

CancellationTokenSource.Cancel

因为你只是不把它扔进这个街区。但是,如果你做了类似的事情:

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

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

现在,请查看示例中的另一个方法:

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和布尔标志 - 更改为该标志将被注意,直到整个睡眠持续时间结束。

所以回答你的问题:在你的例子中,可能会抛出异常,也可能不会抛出异常,具体取决于你取消Thread.Sleep(1000)时当前正在执行的代码部分(我假设使用两个取消令牌源名称CancellationTokenSourcects只是代码中的拼写错误,但如果它是真正的代码 - 则根本不会抛出此类异常,因为您取消tokenSource1但{{{ 1}}等待cts)。