编写Task.WhenAll / WhenAny变量,取消首次出现故障/已取消任务的所有其他任务

时间:2014-03-14 07:49:00

标签: c# asynchronous task-parallel-library .net-4.5 async-await

我是C#的新手,今天开始玩TPL。我决定写一个修改过的版本 任务任务。当所有作为练习。我希望它有以下行为:

  • 在找到出现故障或被取消的第一个任务后,取消其余任务,而不是等待它们完成。
  • 如果任务出现故障,则返回的任务应具有正确的异常集(即不通过继续吞咽并替换为OperationCancelledException())
  • 方法签名中没有异步(希望避免冒泡)。

我提出了以下疯狂/愚蠢的代码,但这些代码无效,我很难想象正在发生的事情。我无法想象任何阻塞正在发生,我想象的是一系列任务,每个任务等待其余的完成。有人可以解释发生了什么吗?

我不会在生产代码中使用它,这只是为了测试我的基础知识。我意识到更简单的方法是执行一个Task.WhenAll并让列表中的任务本身具有继续执行取消失败。

    public static Task WhenAllError(List<Task> tasks, CancellationToken ct)
    {
        var tcs = new TaskCompletionSource<object>();
        return Task.WhenAny(tasks).ContinueWith<Task>((t) =>
             {
                 if (tasks.Count == 0)
                 {
                     tcs.SetResult(null);
                     return tcs.Task;
                 }

                 if (t.IsFaulted)
                 {
                     Console.WriteLine("Task faulted. Cancelling other tasks: {0}", t.Id);
                     cts.Cancel();
                     // Make sure the tasks are cancelled if necessary
                     tcs.SetException(t.Exception);
                     return tcs.Task;
                 }
                 // Similarly handle Cancelled

                 tasks.Remove(t);
                 return WhenAllError(tasks, ct);
             }).Unwrap();
    }

1 个答案:

答案 0 :(得分:2)

CancellationToken类没有Cancel方法。您需要CancellationTokenSource才能取消CancellationToken

同样地影响任务的结果,你需要一个TaskCompletionSource,你不能安全 取消已经运行的任务。见post