取消 CancellationToken 会导致 CancellationToken 异常吗?
Does cancelling a CancellationToken cause a CancellationToken Exception?
我有这段代码,我想就 CancellationToken 的使用获得一些说明。
我阅读了这个关于使用取消令牌和标志之间的区别的问题:
我注意到的一件事是它没有提到异常。所以这是我的问题。 如果调用 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
本身不会抛出此类异常,但它 "moves" 所有相关的取消标记都已取消状态。当某些代码通知取消令牌现在处于取消状态时 - 它 可能 抛出此类异常。如果看你的例子,这部分不会抛出这样的异常:
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)
和布尔标志 - 在整个睡眠持续时间结束之前不会注意到对该标志的更改。
所以回答你的问题:在你的例子中可能会或可能不会抛出异常,这取决于你取消 CancellationTokenSource
时当前正在执行的代码部分(我假设使用两个取消令牌名称为 cts
和 tokenSource1
的源代码只是您代码中的错字,但如果它是真实代码 - 那么根本不会抛出此类异常,因为您取消了 cts
但 Task.Delay
等待 tokenSource1
).
我有这段代码,我想就 CancellationToken 的使用获得一些说明。
我阅读了这个关于使用取消令牌和标志之间的区别的问题:
我注意到的一件事是它没有提到异常。所以这是我的问题。 如果调用 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
本身不会抛出此类异常,但它 "moves" 所有相关的取消标记都已取消状态。当某些代码通知取消令牌现在处于取消状态时 - 它 可能 抛出此类异常。如果看你的例子,这部分不会抛出这样的异常:
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)
和布尔标志 - 在整个睡眠持续时间结束之前不会注意到对该标志的更改。
所以回答你的问题:在你的例子中可能会或可能不会抛出异常,这取决于你取消 CancellationTokenSource
时当前正在执行的代码部分(我假设使用两个取消令牌名称为 cts
和 tokenSource1
的源代码只是您代码中的错字,但如果它是真实代码 - 那么根本不会抛出此类异常,因为您取消了 cts
但 Task.Delay
等待 tokenSource1
).