19

给定一个取消令牌,我想从中创建一个可等待的任务,该任务永远不会完成,但可以取消。我需要这样的模式,IMO应该很常见:

async Task DoStuff(Task t, CancellationToken ct)
{
   // t was made from TaskCompletionSource, 
   // both t and ct are beyond my control

   Task t2 = TaskFromCancellationToken(ct);
   await Task.WhenAny(t, t2);

   // do stuff
}

到目前为止,我得到的最好的想法是:

Task TaskFromCancelationToken(CancellationToken ct)
{
    return Task.Delay(Timeout.Infinite, ct);
}

有没有更好的方法来实现这个逻辑?

4

2 回答 2

24

这不是常见,但它很常见,可以成为我的AsyncEx库的一部分。我使用这样的东西

public static Task AsTask(this CancellationToken cancellationToken)
{
    var tcs = new TaskCompletionSource<object>();
    cancellationToken.Register(() => tcs.TrySetCanceled(),
        useSynchronizationContext: false);
    return tcs.Task;
}

更新:这些天来,我建议使用类似的东西CancellationTokenTaskSource,它可以正确处理所有生命周期,而不会发生资源泄漏。

于 2013-09-07T11:37:59.850 回答
11
Task.Delay(Timeout.Infinite, cancellationToken)

您在问题中建议的答案是据我所知的最佳解决方案。原因如下:

  • 这是安全的
  • 需要非常少的代码
  • 标准库

据我所知,这种Task.Delay方法被很多人大量使用,并且在 Microsoft 博客上也被推荐。MSDN 示例

为什么要自己编写代码(包括测试)来TaskCompletionSource将取消令牌转换为任务?最好利用标准库而不是重新发明轮子;它们比您的代码更有可能没有错误。

于 2018-03-09T02:55:00.543 回答