Partilhar via


Como: Converter um loop OpenMP que usa o tratamento de exceção para usar o tempo de execução de simultaneidade

Este exemplo demonstra como converter um ciclo forparalelo do OpenMP que executa o tratamento de exceções para utilizar o mecanismo de tratamento de exceções do Concurrency Runtime.

Em OpenMP, uma exceção lançada numa região paralela deve ser capturada e manipulada na mesma região pela mesma thread. Uma exceção que escapa da região paralela é capturada pelo manipulador de exceções sem tratamento, que encerra o processo por padrão.

No Concurrency Runtime, quando se lança uma exceção no corpo de uma função de trabalho que se 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 tempo de execução armazena essa exceção e a transmite para o contexto que aguarda a conclusão do grupo de tarefas ou do 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 tempo de execução 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 OpenMP parallel e em uma chamada para parallel_for. A do_work função executa uma solicitação de alocação de memória que não é bem-sucedida e, portanto, lança uma exceção do tipo std::bad_alloc. Na versão que usa OpenMP, o thread que lança a exceção também deve capturá-la. Em outras palavras, cada iteração de um loop paralelo OpenMP deve lidar com a exceção. Na versão que usa o Concurrency Runtime, o thread principal captura uma exceção que é lançada 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 produz o seguinte resultado.

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 OpenMP, a exceção ocorre e é manipulada por cada iteração de loop. Na versão que usa o Concurrency Runtime, o tempo de execução armazena a exceção, interrompe todas as tarefas ativas, descarta as tarefas que ainda não foram iniciadas e encaminha a exceção para o contexto que chama parallel_for.

Se você exigir que a versão que usa OpenMP termine depois que a exceção ocorrer, você pode usar um sinalizador booleano para sinalizar para outras iterações de loop que o erro ocorreu. Como no exemplo no tópico Como: Converter um loop OpenMP que usa cancelamento para usar o Tempo de Execução Concorrente, iterações de loop subsequentes não farão nada se o sinalizador estiver ativo. Por outro lado, se você exigir que o loop que usa o Concurrency Runtime continue depois que a exceção ocorrer, manipule a exceção no próprio corpo do loop paralelo.

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

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, em seguida, execute o seguinte comando em uma janela do prompt de comando do Visual Studio.

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

Ver também

Migrando do OpenMP para o Concurrency Runtime
Tratamento de exceções
Algoritmos paralelos