分享方式:


如何:轉換使用例外狀況處理的 OpenMP 迴圈來使用並行執行階段

此範例示範如何轉換執行例外狀況處理的 OpenMP 平行 for 迴圈,以使用並行執行時間例外狀況處理機制。

在 OpenMP 中,平列區域中擲回的例外狀況必須由同一個執行緒在相同的區域中攔截並處理。 未處理的例外狀況處理常式會攔截逸出平列區域的例外狀況,此處理程式預設會終止進程。

在並行執行時間中,當您在工作 函式的主體中擲回例外狀況時,例如並行::task_group 或並行::structured_task_group 物件,或 平行算法,例如 concurrency::p arallel_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();
}

此範例會產生下列輸出。

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.

在這個使用 OpenMP 的範例版本中,例外狀況會在 中發生,並由每個迴圈反復專案處理。 在使用並行執行時間的版本中,執行時間會儲存例外狀況、停止所有使用中工作、捨棄尚未啟動的任何工作,並將例外狀況封送處理至呼叫 parallel_for 的內容。

如果您要求使用 OpenMP 的版本會在例外狀況發生後終止,您可以使用布林值旗標向其他迴圈反復專案發出錯誤信號。 如同 How to: Convert an OpenMP Loop that Use Cancellation to Use the Concurrency Runtime 主題中的 範例,如果已設定 旗標,後續的迴圈反復專案不會執行任何動作。 相反地,如果您需要在發生例外狀況之後,使用並行執行時間的迴圈會繼續執行,請處理平行迴圈主體本身中的例外狀況。

並行執行時間的其他元件,例如非同步代理程式和輕量型工作,不會傳輸例外狀況。 相反地,未處理的例外狀況處理常式會攔截未處理的例外狀況,而處理常式預設會終止進程。 如需例外狀況處理的詳細資訊,請參閱 例外狀況處理

如需其他平行演算法的詳細資訊 parallel_for ,請參閱 平行演算法

編譯程式碼

複製範例程式碼,並將其貼到 Visual Studio 專案中,或貼到名為 concrt-omp-exceptions.cpp 的檔案中,然後在 Visual Studio 命令提示字元視窗中執行下列命令。

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

另請參閱

從 OpenMP 移轉至並行執行階段
例外狀況處理
平行演算法