[英]Wait for a canceled task to complete before continuing execution
我有以下代碼,可以取消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
?
如果我將WaitAll()
傳遞給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);
}
}
我在這里准備了一個小提琴。
這個問題的標題與我的非常相似,但是不幸的是,所接受的答案與我的情況無關。
您是否知道有什么方法可以實現我所希望的,那就是盡可能充分地使用CancellationToken
?
我認為,如果設置了CancellationToken
則TPL旨在急於完成任務。 您看到此行為的部分原因是因為您正在調用t.Wait(cts.Token)
。 即使設置了令牌,帶CancellationToken
的重載也將停止等待,即使任務尚未完成也是如此。
如果您傳入CancellationToken
,則ContinueWith
也是一樣,只要設置了該令牌,任務就可以完成。
更改代碼以調用t.Wait()
和ContinueWith
而不使用令牌,您將獲得所需的行為。
public static void TaskCancellationTestNotWorking1()
{
try
{
Console.WriteLine("TaskCancellationTestNotWorking started.");
var cts = new CancellationTokenSource();
var t = Task.Run(() =>
{
Console.WriteLine("1");
Thread.Sleep(2000);
Console.WriteLine("2");
}, cts.Token).ContinueWith(task =>
{
Console.WriteLine("3");
Thread.Sleep(2000);
cts.Token.ThrowIfCancellationRequested();
Console.WriteLine("4");
});
Task.Run(() =>
{
Thread.Sleep(1000);
Console.WriteLine("Cancelling...");
cts.Cancel();
}, cts.Token);
try
{
t.Wait();
}
catch (OperationCanceledException)
{
Console.WriteLine("IsCanceled " + t.IsCanceled);
Console.WriteLine("IsCompleted " + t.IsCompleted);
Console.WriteLine("Gracefully canceled.");
}
catch (AggregateException)
{
Console.WriteLine("IsCanceled " + t.IsCanceled);
Console.WriteLine("IsCompleted " + t.IsCompleted);
Console.WriteLine("Gracefully canceled 1.");
}
Console.WriteLine("TaskCancellationTestNotWorking completed.");
}
catch (Exception ex)
{
Console.WriteLine("TaskCancellationTestNotWorking... Failure: " + ex);
}
}
您可能會覺得本文很有用。 如何取消不可取消的異步操作?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.