Como converter um loop OpenMP que usa tratamento de exceções para usar o tempo de execução de simultaneidade
Este exemplo demonstra como converter um loop OpenMP paralelapara que executa a manipulação de exceção para usar o mecanismo de manipulação de exceção em tempo de execução de simultaneidade.
Em OpenMP, uma exceção que é lançada em uma região paralela deve ser capturada e tratado da mesma região pelo mesmo thread. Uma exceção que escape a região paralela é capturada pelo manipulador de exceção sem-tratamento, que encerra o processo por padrão.
Em tempo de execução de simultaneidade, quando você gerencie uma exceção no corpo de uma função de trabalho que você transmita a um grupo de trabalho como um objeto de concurrency::task_group ou de concurrency::structured_task_group , ou um algoritmo paralelo como concurrency::parallel_for, o tempo de execução que armazena exceção e realiza marshaling ao contexto aguardando o grupo de trabalho ou o algoritmo para concluir. Para grupos de trabalho, 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 para todas as tarefas ativas que estão no grupo de trabalho, inclusive aqueles em grupos de trabalho filhos, e em descarta todas as tarefas que ainda não sejam iniciados.
Exemplo
Este exemplo demonstra como tratar exceções em uma região OpenMP em parallel e uma chamada para parallel_for. A função de do_work executa uma solicitação de alocação de memória que não tenha êxito e em virtude disso gerará uma exceção do tipo std::bad_alloc. Na versão que usa OpenMP, o thread que gerou a exceção também deve capturar-la. Ou seja cada iteração do loop paralelos OpenMP deve controlar a exceção. Na versão que usa o tempo de execução de simultaneidade, 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();
}
O exemplo produz a seguinte saída.
Na versão deste exemplo que usa OpenMP, a exceção ocorre no e é tratada por cada iteração do loop. Na versão que usa o tempo de execução de simultaneidade, os repositórios de tempo de execução a exceção, para todas tarefas ativas, em descarta algumas tarefas que ainda não sejam iniciados, e em realiza marshaling a exceção ao contexto que chama parallel_for.
Se você precisar que a versão que usa OpenMP terminar depois que a exceção ocorre, você pode usar um sinalizador booliano para sinalizar a outras interações do 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 de simultaneidade, as iterações subsequentes do loop não criam nada se o sinalizador é definido. Por outro lado, se você requer que o loop que usa o tempo de execução de simultaneidade continuará depois que a exceção ocorre, o tratará a exceção no corpo de loop paralelo em si.
Outros componentes de tempo de execução de simultaneidade, como agentes assíncronas e tarefas de peso leve, não transmitem exceções. Em vez disso, as exceção 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 a manipulação de exceções, consulte Tratamento de exceções no tempo de execução de simultaneidade.
Para obter mais informações sobre como 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 de prompt de comando do Visual Studio.
cl.exe /EHsc /openmp concrt-omp-exceptions.cpp
Consulte também
Conceitos
Migrando de OpenMP no Tempo de Execução de Simultaneidade
Tratamento de exceções no tempo de execução de simultaneidade