如何:转换使用异常处理的 OpenMP 循环以使用并发运行时

本示例演示如何转换执行异常处理的 OpenMP parallel for 循环,以使用并发运行时异常处理机制。

在 OpenMP 中,必须在同一区域中由相同的线程捕获和处理并行区域中引发的异常。 转义并行区域的异常由未经处理的异常处理程序捕获,默认情况下该处理程序会终止进程。

在并发运行时中,当您在传递给任务组(例如 Concurrency::task_groupConcurrency::structured_task_group 对象)或并行算法(例如 Concurrency::parallel_for)的工作函数的主体中引发异常时,运行时会存储该异常并将其封送至等待任务组或算法完成的上下文。 对于任务组,等待上下文是调用 Concurrency::task_group::waitConcurrency::structured_task_group::waitConcurrency::task_group::run_and_waitConcurrency::structured_task_group::run_and_wait 的上下文。 对于并行算法,等待上下文是调用该算法的上下文。 运行时还停止任务组中所有活动的任务(包括子任务组中的活动任务),并放弃任何尚未开始的任务。

示例

本示例演示如何处理 OpenMP parallel 区域和 parallel_for 调用中的异常。 do_work 函数执行不成功并进而引发 std::bad_alloc 类型的异常的内存分配请求。 在使用 OpenMP 的版本中,引发异常的线程还必须捕获该异常。 也就是说,OpenMP 并行循环的每次迭代都必须处理异常。 在使用并发运行时的版本中,由主线程捕获其他线程引发的异常。

// concrt-omp-exceptions.cpp
// compile with: /EHsc /openmp
#include <ppl.h>
#include <new>
#include <iostream>
#include <sstream>

using namespace Concurrency;
using namespace std;

// Demonstrates a function that performs a memory allocation request 
// that does not succeed.
void do_work(int)
{
   // The following memory allocation causes this function to 
   // throw std::bad_alloc.
   char* ptr = new char[(~unsigned int((int)0)/2) - 1];

   // TODO: Assuming that the allocation succeeds, perform some work 
   // and free the allocated memory.

   delete[] ptr;
}

// Demonstrates an OpenMP parallel loop that performs exception handling.
void omp_exception_handling()
{
   #pragma omp parallel for 
      for(int i = 0; i < 10; i++) 
      {
         try {
            // Perform a unit of work.
            do_work(i);
         }
         catch (exception const& e) {
            // Print the error to the console.
            wstringstream ss;
            ss << L"An error of type '" << typeid(e).name() 
               << L"' occurred." << endl;
            wcout << ss.str();
         }
      }
}

// Demonstrates an Concurrency Runtime parallel loop that performs exception handling.
void concrt_exception_handling()
{
   try {
      parallel_for(0, 10, [](int i) 
      {
         // Perform a unit of work.
         do_work(i);
      });
   }
   catch (exception const& e) {
      // Print the error to the console.
      wcout << L"An error of type '" << typeid(e).name() 
            << L"' occurred." << endl;
   }
}

int wmain()
{
   wcout << L"Using OpenMP..." << endl;
   omp_exception_handling();

   wcout << L"Using the Concurrency Runtime..." << endl;
   concrt_exception_handling();
}

该示例产生下面的输出。

Using OpenMP...
An error of type 'class std::bad_alloc' occurred.
An error of type 'class std::bad_alloc' occurred.
An error of type 'class std::bad_alloc' occurred.
An error of type 'class std::bad_alloc' occurred.
An error of type 'class std::bad_alloc' occurred.
An error of type 'class std::bad_alloc' occurred.
An error of type 'class std::bad_alloc' occurred.
An error of type 'class std::bad_alloc' occurred.
An error of type 'class std::bad_alloc' occurred.
An error of type 'class std::bad_alloc' occurred.
Using the Concurrency Runtime...
An error of type 'class std::bad_alloc' occurred.

本示例的版本使用 OpenMP,每次的循环迭代中发生的异常由该循环迭代进行处理。 在使用并发运行时的版本中,运行时存储异常、停止所有活动任务、放弃任何尚未开始的任务,并且将异常封送至调用 parallel_for 的上下文。

如果您需要使用 OpenMP 的版本在异常发生后终止,则可以使用布尔标志向发生错误的其他循环迭代发送信号。 如主题如何:转换使用取消的 OpenMP 循环以使用并发运行时中的示例所示,在设置了标志的情况下,后续的循环迭代不执行任何操作。 相反,如果您需要使用并发运行时的循环在异常发生后继续执行,则在并行循环主体自身中处理异常。

并发运行时的其他组件(例如异步代理和轻量级任务)不会传输异常。 而是由未经处理的异常处理程序来捕获未经处理的异常,默认情况下该处理程序会终止进程。 有关异常处理的更多信息,请参见并发运行时中的异常处理

有关 parallel_for 和其他并行算法的更多信息,请参见并行算法

编译代码

复制该代码示例,并将其粘贴到 Visual Studio 项目中或名为 concrt-omp-exceptions.cpp 的文件中,然后在 Visual Studio 2010 命令提示符窗口中运行以下命令。

cl.exe /EHsc /openmp concrt-omp-exceptions.cpp

请参见

概念

并发运行时中的异常处理

并行算法

其他资源

从 OpenMP 迁移至并发运行时