Freigeben über


Gewusst wie: Konvertieren einer OpenMP-Schleife, in der die Ausnahmebehandlung verwendet wird, zur Verwendung der Concurrency Runtime

In diesem Beispiel wird veranschaulicht, wie eine OpenMP parallel_for-Schleife für die Ausnahmebehandlung konvertiert wird, um den Mechanismus zur Ausnahmebehandlung in der Concurrency Runtime zu verwenden.

In OpenMP müssen Ausnahmen in einem parallelen Bereich im gleichen Bereich und vom gleichen Thread abgefangen und behandelt werden. Eine Ausnahme, die den parallelen Bereich umgeht, wird vom Handler für nicht behandelte Ausnahmen abgefangen, der den Prozess standardmäßig beendet.

In der Concurrency Runtime wird die im Text einer Arbeitsfunktion ausgelöste Ausnahme, die Sie an eine Aufgabengruppe wie ein concurrency::task_group-Objekt oder ein concurrency::structured_task_group-Objekt oder an einen parallelen Algorithmus wie concurrency::parallel_for übergeben, von der Runtime gespeichert und an den Kontext gemarshallt, der darauf wartet, dass die Aufgabengruppe oder der Algorithmus abgeschlossen werden. Der Wartekontext einer Aufgabengruppe ist der Kontext, der eines der folgenden Objekte aufruft: concurrency::task_group::wait, concurrency::structured_task_group::wait, concurrency::task_group::run_and_wait oder concurrency::structured_task_group::run_and_wait. Der Wartekontext eines parallelen Algorithmus ist der Kontext, von dem dieser Algorithmus aufgerufen wurde. Darüber hinaus werden von der Runtime auch alle aktiven Aufgaben in der Aufgabengruppe (sowie alle aktiven Aufgaben in untergeordneten Aufgabengruppen) beendet sowie alle noch nicht gestarteten Aufgaben verworfen.

Beispiel

In diesem Beispiel wird veranschaulicht, wie Ausnahmen in einem OpenMP parallel-Bereich und in einem Aufruf von parallel_for behandelt werden. Die do_work-Funktion führt eine Speicherbelegungsanforderung aus, die nicht erfolgreich ist und daher eine Ausnahme vom Typ std::bad_alloc auslöst. In der Version, die OpenMP verwendet, muss diese vom Thread, der diese Ausnahme auslöst, ebenfalls abgefangen werden. Mit anderen Worten muss die Ausnahme von jeder Iteration einer parallelen OpenMP-Schleife behandelt werden. In der Version mit der Concurrency Runtime wird eine Ausnahme, die von einem anderen Thread ausgelöst wird, vom Hauptthread abgefangen.

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

Folgende Ergebnisse werden zurückgegeben:

  

In der Version in diesem Beispiel mit OpenMP tritt die Ausnahme in der jeweiligen Schleifeniteration auf und wird dort auch behandelt. In der Version mit der Concurrency Runtime wird die Ausnahme von der Laufzeit gespeichert, alle aktiven Aufgaben werden beendet, noch nicht gestartete Aufgaben werden verworfen, und die Ausnahme, die parallel_for aufruft, wird an den Kontext gemarshallt.

Wenn Sie möchten, dass die Version mit OpenMP nach dem Auftreten der Ausnahme beendet wird, können Sie ein boolesche Flag verwenden, um den Fehler gegenüber anderen Schleifeniterationen anzuzeigen. Wie im Beispiel im Thema Gewusst wie: Konvertieren einer OpenMP-Schleife mit Abbruch zur Verwendung der Concurrency Runtime veranschaulicht, hätten nachfolgene Schleifeninterationen keine Auswirkung, wenn das Flag festgelegt ist. Umgekehrt können Sie die Ausnahme, wenn die Schleife mit der Concurrency Runtime nach dem Auftreten der Ausnahme fortgesetzt werden soll, im Text der parallelen Schleife selbst behandeln.

Andere Komponenten der Concurrency Runtime, wie asynchrone Agents und einfache Aufgaben, transportieren keine Ausnahmen. Stattdessen werden unbehandelte Ausnahmen vom Handler für nicht behandelte Ausnahmen abgefangen, der den Prozess standardmäßig beendet. Weitere Informationen zur Behandlung von Ausnahmen finden Sie unter Ausnahmebehandlung in der Concurrency Runtime.

Weitere Informationen zu parallel_for und anderen parallelen Algorithmen finden Sie unter Parallele Algorithmen.

Kompilieren des Codes

Kopieren Sie den Beispielcode, und fügen Sie ihn in ein Visual Studio-Projekt ein. Alternativ dazu können Sie ihn auch in eine Datei mit dem Namen concrt-omp-exceptions.cpp einfügen und dann folgenden Befehl in einem Visual Studio-Eingabeaufforderungsfenster ausführen.

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

Siehe auch

Konzepte

Migrieren von OpenMP zur Concurrency Runtime

Ausnahmebehandlung in der Concurrency Runtime

Parallele Algorithmen