正如i3arnon 已经回答的那样,您可以使用CancellationTokenSource.CreateLinkedTokenSource()
. 当您想区分取消整体任务与取消子任务而不取消整体任务时,我想尝试展示如何使用此类令牌的模式。
async Task MyAsyncTask(
CancellationToken ct)
{
// Keep retrying until the master process is cancelled.
while (true)
{
// Ensure we cancel ourselves if the parent is cancelled.
ct.ThrowIfCancellationRequested();
using var childCts = CancellationTokenSource.CreateLinkedTokenSource(ct);
// Set a timeout because sometimes stuff gets stuck.
childCts.CancelAfter(TimeSpan.FromSeconds(32));
try
{
await DoSomethingAsync(childCts.Token);
}
// If our attempt timed out, catch so that our retry loop continues.
// Note: because the token is linked, the parent token may have been
// cancelled. We check this at the beginning of the while loop.
catch (OperationCancelledException) when (childCts.IsCancellationRequested)
{
}
}
}
当临时令牌到期时,不得取消主令牌。
注意MyAsyncTask()
's 签名接受CancellationToken
而不是CancellationTokenSource
. 由于该方法只能访问 上的成员CancellationToken
,因此它不会意外取消主/父令牌。我建议您以这样一种方式组织您的代码,即CancellationTokenSource
主任务的代码对尽可能少的代码可见。在大多数情况下,这可以通过传递CancellationTokenSource.Token
给方法而不是共享对CancellationTokenSource
.
我没有调查过,但可能有一种类似反射的方法可以强制取消 aCancellationToken
而不访问它的CancellationTokenSource
. 希望这是不可能的,但如果可能的话,这将被认为是不好的做法,一般不用担心。