2016-11-14 48 views
1

我有一個運行任務清單,其編號爲CancellationTokenSourceTask.WaitAll引發OperationCanceledException

我希望當前線程一直等到所有任務完成,直到任務被取消。

Task.WaitAll(tasks.ToArray(), searchCencellationTokenSource.Token); 
System.Console.WriteLine("Done !"); 

即使當前線程處於等待狀態,任務可能會被另一個任務取消。這是正常的行爲。

但是,噹噹前線程處於等待狀態並且另一個任務取消任務時,WaitAll會向CancellationTokenSource拋出一條消息:「操作已取消。」。

我知道它被取消了,我故意這樣做了。我只是希望它在任務被取消或完成後繼續執行下一個代碼,而不會引發異常。

我知道我可以用try & catch來包裝這段代碼,但拋出一個異常很繁重,我不希望它發生在像這樣的正常行爲上。

+0

這是[記錄](https://msdn.microsoft.com/en-us/library/dd321280(v = vs.110).aspx)。如果你不想得到異常,爲什麼你將'CancellationToken'傳遞給'WaitAll'? –

+0

我通過它來取消等待,但不幸的是,即使我沒有通過它,它也會拋出這個異常。 @IvanStoev – Jacob

+4

它也記錄瞭如果至少有一個任務被取消,你會得到'AggregateException'。不管你想不想,這就是他們設計的方式,除了使用'try/catch'之外別無選擇。 –

回答

2

這種阻塞機制可以表述爲:

Task.WhenAll(taskA, taskB, taskC).Wait() 

這給你一個任務回來,我們可以等待,但也可以從管理取消。所以,忽略消除異常,可以進行以下操作:

Task.WhenAll(taskA, taskB, taskC).ContinueWith(t => { }, TaskContinuationOptions.OnlyOnCanceled).Wait(); 

,不會拋出OperationCancelledException

這可能隨後被包裹成一個擴展方法如下:

public static class TaskExtensions 
{ 
    public static Task IgnoreCancellation(this Task task) 
    { 
     return task.ContinueWith(t => { }, TaskContinuationOptions.OnlyOnCanceled); 
    } 
} 

這將讓你沒有遇到一個OperationCancelledException寫以下,再次:

Task.WhenAll(taskA, taskB, taskC).IgnoreCancellation().Wait(); 

這是一個測試夾具的表現工作方法:

public class IgnoreTaskCancellation 
{ 
    [Fact] 
    public void ShouldThrowAnAggregateException() 
    { 
     CancellationTokenSource cts = new CancellationTokenSource(10); 

     Task taskA = Task.Delay(20, cts.Token); 
     Task taskB = Task.Delay(20, cts.Token); 
     Task taskC = Task.Delay(20, cts.Token); 

     Assert.Throws<AggregateException>(() => Task.WhenAll(taskA, taskB, taskC).Wait()); 
    } 

    [Fact] 
    public void ShouldNotThrowAnException() 
    { 
     CancellationTokenSource cts = new CancellationTokenSource(10); 

     Task taskA = Task.Delay(20, cts.Token); 
     Task taskB = Task.Delay(20, cts.Token); 
     Task taskC = Task.Delay(20, cts.Token); 

     Task.WhenAll(taskA, taskB, taskC).ContinueWith(t => { }, TaskContinuationOptions.OnlyOnCanceled).Wait(); 
    } 

    [Fact] 
    public void ShouldNotThrowAnExceptionUsingIgnore() 
    { 
     CancellationTokenSource cts = new CancellationTokenSource(10); 

     Task taskA = Task.Delay(20, cts.Token); 
     Task taskB = Task.Delay(20, cts.Token); 
     Task taskC = Task.Delay(20, cts.Token); 

     Task.WhenAll(taskA, taskB, taskC).IgnoreCancellation().Wait(); 
    } 
} 

希望它hel PS。

+0

謝謝你的回答。我認爲這是一種解決方法。也許你有這樣的代碼在生產上運行嗎?如果是這樣,它運行正常嗎? – Jacob

+0

@Jacob按設計它會拋出異常,但你不想要。所以你確實在尋找解決方法。 – Steve

+0

它運作良好,謝謝! – Jacob

相關問題