Partilhar via


Como converter um loop OpenMP que usa tratamento de exceções para usar o runtime de simultaneidade

Este exemplo demonstra como converter um OpenMP paralelopara loop que executa o tratamento de exceção para usar o mecanismo de tratamento de exceção de Runtime de Simultaneidade.

No OpenMP, uma exceção gerada em uma região paralela deve ser capturada e tratada na mesma região pelo mesmo thread. Uma exceção que escapa da região paralela é capturada pelo manipulador de exceção sem tratamento, que encerra o processo por padrão.

No Runtime de Simultaneidade, quando você lança uma exceção no corpo de uma função de trabalho que você passa para um grupo de tarefas, como um objeto concurrency::task_group ou concurrency::structured_task_group ou para um algoritmo paralelo, como concurrency::parallel_for, o runtime armazena essa exceção e faz marshaling dela para o contexto que aguarda a conclusão do grupo de tarefas ou algoritmo. Para grupos de tarefas, o contexto de espera é o contexto que chama concurrency::task_group::wait, concurrency::structured_task_group::wait, concurrency::task_group::run_and_wait ou concurrency::structured_task_group::run_and_wait. Para um algoritmo paralelo, o contexto de espera é o contexto que chamou esse algoritmo. O runtime também interrompe todas as tarefas ativas que estão no grupo de tarefas, incluindo aquelas em grupos de tarefas filho, e descarta todas as tarefas que ainda não foram iniciadas.

Exemplo

Este exemplo demonstra como lidar com exceções em uma região parallel do OpenMP e em uma chamada para parallel_for. A função do_work executa uma solicitação de alocação de memória que não tem êxito e, portanto, gera uma exceção do tipo std::bad_alloc. Na versão que usa o OpenMP, o thread que gera a exceção também deve detectá-la. Em outras palavras, cada iteração de um loop paralelo do OpenMP deve lidar com a exceção. Na versão que usa o Runtime de Simultaneidade, o thread principal captura uma exceção gerada por outro thread.

// 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();
}

Este exemplo gerencia a seguinte saída.

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.

Na versão deste exemplo que usa o OpenMP, a exceção ocorre e é tratada por cada iteração de loop. Na versão que usa o Runtime de Simultaneidade, o runtime armazena a exceção, interrompe todas as tarefas ativas, descarta todas as tarefas que ainda não foram iniciadas e faz marshaling da exceção para o contexto que chama parallel_for.

Se precisar que a versão que usa o OpenMP seja encerrada após a exceção ocorrer, você poderá usar um sinalizador booliano para sinalizar para outras iterações de loop que o erro ocorreu. Como no exemplo no tópico Como converter um loop do OpenMP que usa cancelamento para o uso do Runtime de Simultaneidade, iterações de loop subsequentes não farão nada se o sinalizador estiver definido. Por outro lado, se você exigir que o loop que usa o Runtime de Simultaneidade continue após a exceção ocorrer, manipule a exceção no próprio corpo do loop paralelo.

Outros componentes do Runtime de Simultaneidade, como agentes assíncronos e tarefas leves, não transportam exceções. Em vez disso, exceções sem tratamento são capturadas pelo manipulador de exceção sem tratamento, que encerra o processo por padrão. Para obter mais informações sobre o tratamento de exceção, consulte Tratamento de exceção.

Para obter mais informações sobre parallel_for e outros algoritmos paralelos, consulte Algoritmos paralelos.

Compilando o código

Copie o código de exemplo e cole-o em um projeto do Visual Studio, ou cole-o em um arquivo chamado concrt-omp-exceptions.cpp e execute o comando a seguir em uma janela do Prompt de comando do Visual Studio.

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

Confira também

Migrando do OpenMP para o runtime de simultaneidade
Tratamento de exceção
Algoritmos paralelos