I am trying to allow cancellation of a Parallel.ForEach
loop. According to this MSDN article, it is possible, and I am following their coding.
// Tokens for cancellation
ParallelOptions po = new ParallelOptions();
po.CancellationToken = cts.Token;
try
{
Parallel.ForEach(queries, po, (currentQuery) =>
{
// Execute query
ExecuteQuery(currentQuery);
// Throw exception if cancelled
po.CancellationToken.ThrowIfCancellationRequested(); // ***
});
}
catch (OperationCanceledException cancelException)
{
Console.WriteLine(cancelException.Message);
}
However, when I call cts.Cancel();
from a user-accessible function, the app crashes on the line marked with asterisks above with the error:
System.OperationCanceledException was unhandled by user code
Message=The operation was canceled.
Source=mscorlib
StackTrace:
at System.Threading.CancellationToken.ThrowIfCancellationRequested()
at CraigslistReader.SearchObject.<>c__DisplayClass7.<bw_DoWork>b__5(Query currentQuery) in {PATH}:line 286
at System.Threading.Tasks.Parallel.<>c__DisplayClass2d`2.<ForEachWorker>b__23(Int32 i)
at System.Threading.Tasks.Parallel.<>c__DisplayClassf`1.<ForWorker>b__c()
InnerException:
I have the Exception handler right there, so I don't understand the crash. Any ideas?
For and Parallel. ForEach overloads do not have any special mechanism to handle exceptions that might be thrown. In this respect, they resemble regular for and foreach loops ( For and For Each in Visual Basic); an unhandled exception causes the loop to terminate as soon as all currently running iterations finish.
Cancel a Parallel. For or Parallel. ForEach loop in . NET by supplying a cancellation token object to the method in the ParallelOptions parameter.
When you add your own exception-handling logic to parallel loops, each exception should be catched and saved to a list(Use Concurrent Queue), because each loop will create different exception. So after the loop exists we can wrap all exceptions from the list in a System. AggregateException and throw it.
The issue is that po.CancellationToken.ThrowIfCancellationRequested();
is explicitly throwing an exception, which is unhandled. The exception handler may be around the Parrallel.ForEach()
call but the exception is not handled within the lambda expression. Either remove the line or add an exception handler within the lambda expression and it should work.
See Cancelling a Task is throwing an exception for more information.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With