我对c#相当陌生,今天开始使用TPL。我决定写一个修改版本的任务任务。WhenAll作为练习。我希望它具有以下行为:
- 在发现第一个出现故障或被取消的任务后,取消其余的任务,而不是等待它们完成。
- 如果任务出错,返回的任务应该有正确的异常设置(即不通过继续吞下并替换为OperationCancelledException()))
- 方法签名中没有async(想要避免冒泡)。
我想出了下面这段疯狂/愚蠢的代码,它不起作用,我很难想象发生了什么。我无法想象会有任何阻塞发生,我所想象的是一连串的任务,每个任务都在等待其他任务完成。有人能解释一下这是怎么回事吗?
我不会在生产代码中使用它,这只是为了测试我的基础。我意识到一个更简单的方法是做一个任务。WhenAll和list中的任务本身具有执行失败时取消的延续。
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();
}
CancellationToken
类没有Cancel
方法。你需要一个CancellationTokenSource
来抵消CancellationToken
。
同样,为了影响任务的结果,你需要一个不能安全的TaskCompletionSource
取消正在运行的任务。看这篇文章