Cara: Mengonversi Perulangan OpenMP yang Menggunakan Penanganan Pengecualian untuk Menggunakan Runtime Konkurensi

Contoh ini menunjukkan cara mengonversi paralelOpenMP untuk perulangan yang melakukan penanganan pengecualian untuk menggunakan mekanisme penanganan pengecualian Runtime Konkurensi.

Di OpenMP, pengecualian yang dilemparkan di wilayah paralel harus ditangkap dan ditangani di wilayah yang sama dengan utas yang sama. Pengecualian yang lolos dari wilayah paralel ditangkap oleh handler pengecualian yang tidak tertangani, yang mengakhiri proses secara default.

Dalam Runtime Konkurensi, saat Anda memberikan pengecualian dalam isi fungsi kerja yang Anda teruskan ke grup tugas seperti konkurensi::task_group atau konkurensi::structured_task_group objek, atau ke algoritma paralel seperti konkurensi::p arallel_for, runtime menyimpan pengecualian dan marsekalnya ke konteks yang menunggu grup tugas atau algoritma selesai. Untuk grup tugas, konteks tunggu adalah konteks yang memanggil konkurensi::task_group::wait, concurrency::structured_task_group::wait, concurrency::task_group::run_and_wait, atau concurrency::structured_task_group::run_and_wait. Untuk algoritma paralel, konteks tunggu adalah konteks yang memanggil algoritma tersebut. Runtime juga menghentikan semua tugas aktif yang ada dalam grup tugas, termasuk tugas dalam grup tugas turunan, dan membuang tugas apa pun yang belum dimulai.

Contoh

Contoh ini menunjukkan cara menangani pengecualian di wilayah OpenMP parallel dan dalam panggilan ke parallel_for. Fungsi ini do_work melakukan permintaan alokasi memori yang tidak berhasil dan oleh karena itu melemparkan pengecualian jenis std::bad_alloc. Dalam versi yang menggunakan OpenMP, utas yang melempar pengecualian juga harus menangkapnya. Dengan kata lain, setiap iterasi perulangan paralel OpenMP harus menangani pengecualian. Dalam versi yang menggunakan Runtime Konkurensi, utas utama menangkap pengecualian yang dilemparkan oleh utas lain.

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

Contoh ini menghasilkan output berikut.

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.

Dalam versi contoh ini yang menggunakan OpenMP, pengecualian terjadi di dan ditangani oleh setiap perulangan perulangan. Dalam versi yang menggunakan Runtime Konkurensi, runtime menyimpan pengecualian, menghentikan semua tugas aktif, membuang tugas apa pun yang belum dimulai, dan marshal pengecualian untuk konteks yang memanggil parallel_for.

Jika Anda mengharuskan versi yang menggunakan OpenMP berakhir setelah pengecualian terjadi, Anda dapat menggunakan bendera Boolean untuk memberi sinyal ke iterasi perulangan lain bahwa kesalahan terjadi. Seperti dalam contoh dalam topik Cara: Mengonversi Perulangan OpenMP yang Menggunakan Pembatalan untuk Menggunakan Runtime Konkurensi, iterasi perulangan berikutnya tidak akan melakukan apa pun jika bendera diatur. Sebaliknya, jika Anda mengharuskan perulangan yang menggunakan Runtime Konkurensi berlanjut setelah pengecualian terjadi, tangani pengecualian dalam isi perulangan paralel itu sendiri.

Komponen lain dari Runtime Konkurensi, seperti agen asinkron dan tugas ringan, tidak mengangkut pengecualian. Sebaliknya, pengecualian yang tidak tertangani ditangkap oleh handler pengecualian yang tidak tertangani, yang mengakhiri proses secara default. Untuk informasi selengkapnya tentang penanganan pengecualian, lihat Penanganan Pengecualian.

Untuk informasi selengkapnya tentang parallel_for dan algoritma paralel lainnya, lihat Algoritma Paralel.

Mengompilasi Kode

Salin kode contoh dan tempelkan dalam proyek Visual Studio, atau tempelkan dalam file yang diberi nama concrt-omp-exceptions.cpp lalu jalankan perintah berikut di jendela Prompt Perintah Visual Studio.

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

Baca juga

Migrasi dari OpenMP ke Runtime Konkurensi
Penanganan Pengecualian
Algoritma Paralel