Практическое руководство. Преобразование цикла OpenMP, использующего обработку исключений для использования среды выполнения с параллелизмом
В этом примере показано, как преобразовать цикл OpenMP parallel for, позволяющий использовать механизм обработки исключений среды выполнения с параллелизмом.
В OpenMP исключение, возникшее в параллельной области, должно быть перехвачено и обработано в той же области тем же потоком. Исключение, покинувшее параллельную область, перехватывается обработчиком необработанных исключений, который по умолчанию завершает процесс.
В среде выполнения с параллелизмом при создании исключения в основной части рабочей функции, передаваемой такой группе задач, как объект concurrency::task_group или concurrency::structured_task_group, либо такому параллельному алгоритму, как concurrency::parallel_for, среда выполнения сохраняет это исключение и маршалирует его в контекст, ожидающий завершения группы задач или алгоритма. Для групп задач ожидающим контекстом является контекст, вызывающий метод concurrency::task_group::wait, concurrency::structured_task_group::wait, concurrency::task_group::run_and_wait или concurrency::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();
}
В результате выполнения примера получается следующий результат:
В версии этого примера, использующей OpenMP, исключение возникает и обрабатывается в каждой итерации цикла. В версии, использующей среду выполнения с параллелизмом, среда выполнения сохраняет исключение, останавливает все активные задачи, удаляет все не начатые задачи и маршалирует исключение в контекст, вызывающий метод parallel_for.
Если нужно, чтобы версия, использующая OpenMP, завершала работу после возникновения исключения, можно использовать логический флаг, указывающий другим итерациям цикла, что произошла ошибка. Если задан этот флаг, последующие итерации не будут делать ничего, как в примере в разделе Практическое руководство. Преобразование цикла OpenMP, использующего отмену для использования среды выполнения с параллелизмом. И наоборот, если нужно, чтобы цикл, использующий среду выполнения с параллелизмом, продолжал работу после возникновения исключения, следует обрабатывать исключение в самом основной части параллельного цикла.
Другие компоненты среды выполнения с параллелизмом, например асинхронные агенты и упрощенные задачи, не транспортируют исключения. Вместо этого необработанные исключения перехватываются обработчиком необработанных исключений, который по умолчанию завершает процесс. Дополнительные сведения об обработке исключений см. в разделе Обработка исключений в среде выполнения с параллелизмом.
Дополнительные сведения об алгоритме parallel_for и других параллельных алгоритмах см. в разделе Параллельные алгоритмы.
Компиляция кода
Скопируйте пример кода и вставьте его в проект Visual Studio или файл с именем concrt-omp-exceptions.cpp, затем выполните в окне командной строки Visual Studio следующую команду.
cl.exe /EHsc /openmp concrt-omp-exceptions.cpp
См. также
Основные понятия
Переход от OpenMP к среде выполнения с параллелизмом