【发布时间】:2014-08-28 03:51:20
【问题描述】:
我有以下代码,其中可以取消Task,但我基本上需要等待它完成(以确保完整性),然后再将OperationCanceledException 扔给调用者。
public static void TaskCancellationTest() {
try {
Console.WriteLine("TaskCancellationTest started.");
var cts = new CancellationTokenSource();
var t = Task.Run(() => {
if (cts.Token.IsCancellationRequested) return;
Console.WriteLine("1");
Task.Delay(2000).Wait();
Console.WriteLine("2");
}).ContinueWith(task => {
if (cts.Token.IsCancellationRequested) return;
Console.WriteLine("3");
Task.Delay(2000).Wait();
Console.WriteLine("4");
});
Task.Run(() => {
Task.Delay(1000).Wait();
Console.WriteLine("Cancelling...");
cts.Cancel();
});
t.Wait();
try {
cts.Token.ThrowIfCancellationRequested();
}
catch (OperationCanceledException) {
Console.WriteLine("Gracefully canceled.");
}
Console.WriteLine("TaskCancellationTest completed.");
}
catch (Exception ex) {
Console.WriteLine("TaskCancellationTest... Failure: " + ex);
}
}
正如预期的那样,结果是:
1
Cancelling...
2
Gracefully canceled.
它有效,但我更愿意将CancellationToken 传递给方法,因为我知道这是一个更好的模式。我还希望能够观察方法体内的令牌并调用ThrowIfCancellationRequested() 中止,而不必等待下一个ContinueWith()。
我正在使用以下替代代码,它也可以工作,但有没有办法让OperationCanceledException 引发而不是AggregateException?
如果我将cancellationToken 传递给WaitAll() 方法,问题是它会在取消令牌后立即抛出OperationCanceledException,而不是等待任务t1 和t2 实际完成(它们将继续在后台运行),然后只抛出异常。
public static void TaskCancellationTest2() {
try {
Console.WriteLine("TaskCancellationTest2 started.");
var cts = new CancellationTokenSource();
var t1 = Task.Run(() => {
Console.WriteLine("1");
Task.Delay(2000).Wait();
Console.WriteLine("2");
}, cts.Token);
var t2 = t1.ContinueWith(task => {
Console.WriteLine("3");
Task.Delay(2000).Wait();
cts.Token.ThrowIfCancellationRequested();
Console.WriteLine("4");
}, cts.Token);
Task.Run(() => {
Task.Delay(1000).Wait();
Console.WriteLine("Cancelling...");
cts.Cancel();
});
try {
try {
Task.WaitAll(t1, t2);
}
catch (AggregateException ae) {
if (ae.InnerExceptions.Count == 1 && ae.InnerExceptions.Single() is OperationCanceledException) {
throw ae.InnerExceptions.Single();
}
throw;
}
}
catch (OperationCanceledException) {
Console.WriteLine("Gracefully canceled.");
}
Console.WriteLine("TaskCancellationTest2 completed.");
}
catch (Exception ex) {
Console.WriteLine("TaskCancellationTest2... Failure: " + ex);
}
}
我准备了一把小提琴here。
This question 的标题与我的非常相似,但不幸的是,接受的答案与我的情况无关。
你知道有什么方法可以实现我想要的,尽可能地利用CancellationToken吗?
【问题讨论】:
标签: c# design-patterns asynchronous task cancellation