Postupy: Převedení smyčky OpenMP využívající zpracování výjimek na využití modulu Concurrency Runtime
Tento příklad ukazuje, jak převést paralelněOpenMP pro smyčku, která provádí zpracování výjimek pomocí mechanismu zpracování výjimek Concurrency Runtime.
V OpenMP musí být výjimka, která je vyvolána v paralelní oblasti, zachycena a zpracována ve stejné oblasti stejným vláknem. Výjimka, která uchytí paralelní oblast, je zachycena neošetřenou obslužnou rutinou výjimky, která ukončuje proces ve výchozím nastavení.
Když v modulu Concurrency Runtime vyvoláte výjimku v těle pracovní funkce, kterou předáte skupině úloh, jako je například souběžnost::task_group nebo souběžnost::structured_task_group objekt nebo paralelní algoritmus, například concurrency::p arallel_for, modul runtime uloží tuto výjimku a zařadí ji do kontextu, který čeká na dokončení skupiny úloh nebo algoritmu. U skupin úloh je kontext čekání, který volá souběžnost::task_group::wait, concurrency:::structured_task_group::wait, concurrency::task_group::run_and_wait nebo concurrency::structured_task_group::run_and_wait. U paralelního algoritmu je kontext čekání kontext, který tento algoritmus nazval. Modul runtime také zastaví všechny aktivní úlohy, které jsou ve skupině úloh, včetně těch v podřízených skupinách úkolů, a zahodí všechny úkoly, které ještě nebyly spuštěny.
Příklad
Tento příklad ukazuje, jak zpracovat výjimky v oblasti OpenMP parallel
a volání parallel_for
. Funkce do_work
provede žádost o přidělení paměti, která není úspěšná, a proto vyvolá výjimku typu std::bad_alloc. Ve verzi, která používá OpenMP, musí vlákno, které vyvolá výjimku, zachytit také. Jinými slovy, každá iterace paralelní smyčky OpenMP musí zpracovat výjimku. Ve verzi, která používá Concurrency Runtime, hlavní vlákno zachytí výjimku, která je vyvolán jiným vláknem.
// 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();
}
Tento příklad vytvoří následující výstup.
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.
Ve verzi tohoto příkladu, která používá OpenMP, dojde k výjimce a je zpracována každou iterací smyčky. Ve verzi, která používá Concurrency Runtime, modul runtime uloží výjimku, zastaví všechny aktivní úlohy, zahodí všechny úkoly, které ještě nebyly spuštěny, a zařadí výjimku do kontextu, který volá parallel_for
.
Pokud potřebujete, aby se verze používající OpenMP po výjimce ukončila, můžete pomocí logického příznaku signalizovat další iterace smyček, ke kterým došlo k chybě. Stejně jako v příkladu v tématu Postupy: Převod smyčky OpenMP, která používá zrušení k použití modulu Concurrency Runtime, následné iterace smyčky by nedělaly nic, pokud je příznak nastaven. Pokud naopak vyžadujete, aby smyčka, která používá Concurrency Runtime, pokračovala po výskytu výjimky, zpracovat výjimku v samotném těle paralelní smyčky.
Jiné komponenty modulu Concurrency Runtime, jako jsou asynchronní agenti a zjednodušené úlohy, nepřevozují výjimky. Místo toho jsou neošetřené výjimky zachyceny neošetřenou obslužnou rutinou výjimky, která ukončuje proces ve výchozím nastavení. Další informace o zpracovánívýjimekch
Další informace o parallel_for
paralelních algoritmech a dalších paralelních algoritmech najdete v tématu Paralelní algoritmy.
Probíhá kompilace kódu
Zkopírujte ukázkový kód a vložte ho do projektu sady Visual Studio nebo ho vložte do pojmenovaného concrt-omp-exceptions.cpp
souboru a potom v okně příkazového řádku sady Visual Studio spusťte následující příkaz.
cl.exe /EHsc /openmp concrt-omp-exceptions.cpp
Viz také
Migrace z OpenMP do Concurrency Runtime
Zpracování výjimek
Paralelní algoritmy