Unhandled OperationCanceledException when thrown from Parallel.ForEach

Doug picture Doug · Sep 24, 2012 · Viewed 12.9k times · Source

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?

Answer

akton picture akton · Sep 24, 2012

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.