如何:轉換使用例外狀況處理的 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 的版本在例外狀況發生之後結束,可以使用 Boolean 旗標對發生錯誤的其他迴圈反覆項目發出信號。 如 如何:轉換使用取消的 OpenMP 迴圈來使用並行執行階段主題的範例所示,如果設定了旗標,後續迴圈反覆項目就不會執行任何動作。 相反地,如果您需要使用並行執行階段的迴圈在例外狀況發生之後繼續進行,請在平行迴圈主體本身內處理例外狀況。
並行執行階段的其他元件 (例如非同步代理程式和輕量型工作) 不會傳輸例外狀況。 而未處理例外狀況是由未處理例外處理常式攔截,而該處理常式預設會結束處理序。 如需例外狀況處理的詳細資訊,請參閱並行執行階段的例外狀況處理。
如需 parallel_for 和其他平行演算法的詳細資訊,請參閱平行演算法。
編譯程式碼
請複製範例程式碼並將它貼在 Visual Studio 專案中,或是貼在名為 concrt-omp-exceptions.cpp 的檔案中,然後在 Visual Studio 的 [命令提示字元] 視窗中執行下列命令。
cl.exe /EHsc /openmp concrt-omp-exceptions.cpp