Reputation: 31
I have a question on TPL tasks. I have some tasks that are a "Show Stoppers", once one of them is faulted i dont want the method to continue running but give an exception and exit. I tried using TaskContinuationOptions, something like this:
var res = Task.Factory.ContinueWhenAny(
new[] { task1, task2, task3},
task =>
{
throw task.Exception.Flatten();
},
CancellationToken.None,
TaskContinuationOptions.OnlyOnFaulted,
this.taskScheduler);
var res1 = Task.Factory.ContinueWhenAll(
new[] { task1, task2, task3},
tasks =>
{
// DO SOME CODE
},
CancellationToken.None,
TaskContinuationOptions.NotOnFaulted,
this.taskScheduler);
return Task.WhenAny(res, res1).Unwrap();
But unfortunately there is a limitation filtering on a TaskContinuationOptions when continuing on more that a one task. What is the solution to this?
Upvotes: 2
Views: 2141
Reputation: 1418
You can use a CancellationTokenSource and run all your tasks with this cancellation token , so if the token is cancelled then rest of tasks will be cancelled as well
var cs = new CancellationTokenSource();
var options = new ParallelOptions { CancellationToken = cs.Token };
var array = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
try
{
Parallel.ForEach(array, options, (index) =>
{
CallCustomMethod(cs, index);
});
}
catch (OperationCanceledException ex)
{
}
void CallCustomMethod(CancellationTokenSource cs, int index)
{
try
{
if (cs.IsCancellationRequested)
{
return;
}
if (index == 4)
{
throw new Exception("Cancel");
}
Console.WriteLine(index);
}
catch
{
cs.Cancel();
}
}
Upvotes: 0
Reputation: 149628
You can implement a loop which checks if the tasks are faulted as they finish. If one of them faults, you could throw and exit the method:
List<Task> tasks = new List<Task> {task1, task2, task3}; // Show stopping tasks.
while (tasks.Count > 0)
{
var finishedTask = await Task.WhenAny(tasks);
tasks.Remove(finishedTask);
if (finishedTask.Status == TaskStatus.Faulted)
{
// Throw and exit the method.
}
}
// Continuation code goes here.
Note this will not cancel the other ongoing tasks. You could implement a cancelling mechanism if needed using CancellationToken
and explicitly cancel the remaining tasks. Your tasks will need to monitor the cancellation token to see if there was a request for cancellation, either by looking at CancellationToken.IsCancellationRequested
property or by using the CancellationToken.ThrowIfCancellationRequested
method:
var cts = new CancellationTokenSource();
// Generate some tasks for this example.
var task1 = Task.Run(async () => await Task.Delay(1000, cts.Token), cts.Token);
var task2 = Task.Run(async () => await Task.Delay(2000, cts.Token), cts.Token);
var task3 = Task.Run(async () => await Task.Delay(3000, cts.Token), cts.Token);
List<Task> tasks = new List<Task> {task1, task2, task3};
while (tasks.Count > 0)
{
var finishedTask = await Task.WhenAny(tasks);
tasks.Remove(finishedTask);
if (finishedTask.Status == TaskStatus.Faulted)
{
cts.Cancel();
// Throw and exit the method.
}
}
Upvotes: 1