我有以下代码,其中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
?
如果我不叫't.Wait()','然后Console.WriteLine( “2”);'会后'TaskCancellationTestNotWorking异步执行( )'会返回。这是我需要避免的(如果我正在编写文件而不是写入“2”,则需要确保TaskCancellationTestNotWorking()不会在文件写入操作完成之前返回)。 – 2014-08-28 04:49:27
如果任务处于“已取消”状态,则“IsCompleted”将返回true,尽管它仍可能正在执行代码。 – 2014-08-28 04:51:12
你已经调用了'Wait()'并且它抛出了一个异常,你为什么要再次调用它? – 2014-08-28 06:08:24