gpt4 book ai didi

c# - 在任务执行委托(delegate)中延迟取消支持的正确方法是什么?

转载 作者:行者123 更新时间:2023-11-30 17:44:17 32 4
gpt4 key购买 nike

我没有在 MSDN 或此处看到任何关于如何完成此操作的具体提及。用例有些模糊,但我怀疑仍然有效。

var cancel = new CancellationTokenSource();
var task = Task.Factory.StartNew(() => { Task.Delay(1000, cancel.Token).Wait(); }, cancel.Token);
cancel.CancelAfter(100);
task.Wait();

以上代码将尝试在 100 毫秒后取消包含分离 子延迟任务的任务,并等待task 完成,这将生成 AggregateException(由于取消)。问题在于 task 出现故障而不是被取消。这是预期的行为,因为延迟任务未附加到父 task,即使两者共享相同的取消 token 。

我的问题具体涉及如何将 Task.Delay 附加到已在运行的任务。如果您有权访问父任务,甚至可以这样做吗?如果无法访问父任务实例或无法访问父任务实例,那么处理这种情况的正确方法是什么?

我能想到的最好的解决方法是将延迟任务的 Wait 包装在 try/finally block 中,并明确尝试使任务取消冒泡。

try { Task.Delay(1000, cancel.Token).Wait(); } finally { cancel.Token.ThrowIfCancellationRequested(); }

虽然有效,但感觉不太对,但我不确定是否有更好的方法来实现这一点。期望的结果是,如果发生取消,父任务将转到 Canceled 而不是 Faulted。因此,如果取消的起源发生在分离的子任务中,父任务仍应转换为 Canceled

注意:我故意在这里省略了 async/await,只是因为它似乎并没有改变问题或结果。如果不是这种情况,请提供示例。

最佳答案

因此,当 OperationCanceledException 被抛出且未在其中捕获且其关联的 CancellationToken 被取消时,任务被视为已取消。

在您的情况下,抛出的异常是AggregateException包含 TaskCanceledException(这是一个OperationCanceledException)而不是直接 TaskCanceledException

有一种简单的方法可以解决这个问题。您可以使用 task.GatAwaiter().GetResult(),而不是使用 Task.Wait 同步阻塞,后者将任何异常包装在 AggregateException 包装器中。这就是 awaitasync-await 中使用的内容。它抛出原始异常,如果有多个异常,它抛出第一个异常:

var cancel = new CancellationTokenSource();
var task = Task.Factory.StartNew(() => { Task.Delay(1000, cancel.Token).GetAwaiter().GetResult(); }, cancel.Token);
cancel.CancelAfter(100);
task.Wait();

如果您使用了 async-await,您就不会遇到这个问题,因为与 Task.Wait 不同,它会抛出 TaskCanceledException 本身:

var cancel = new CancellationTokenSource();
var task = Task.Run(() => Task.Delay(1000, cancel.Token), cancel.Token);
cancel.CancelAfter(100);
task.Wait();

我假设这只是一个例子。实际生产代码不应该与此类似,因为您在异步操作上同步阻塞,而异步操作又在异步操作上同步阻塞。

关于c# - 在任务执行委托(delegate)中延迟取消支持的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29837461/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com