Ausnahmebehandlung in der Concurrency Runtime

Die Concurrency Runtime übermittelt viele Arten von Fehlern mithilfe der C++-Ausnahmebehandlung. Zu diesen Fehlern zählen die falsche Verwendung der Runtime, Runtime-Fehler wie etwa das Nichtabrufen einer Ressource sowie Fehler, die in Arbeitsfunktionen auftreten, die Sie für Aufgaben und Aufgabengruppen bereitstellen. Wenn eine Aufgabe oder eine Aufgabengruppe eine Ausnahme auslöst, wird diese Ausnahme von der Runtime gespeichert und an den Kontext gemarshallt, der wartet, bis die Aufgabe oder Aufgabengruppe beendet wird. Bei Komponenten wie bei einfachen Aufgaben und Agents verwaltet die Runtime keine Ausnahmen. In diesen Fällen müssen Sie einen eigenen Mechanismus für die Ausnahmenbehandlung implementieren. In diesem Thema wird beschrieben, wie die Runtime Ausnahmen behandelt, die von Aufgaben, Aufgabengruppen, einfachen Aufgaben und asynchronen Agents ausgelöst werden, und wie auf Ausnahmen von den Anwendungen reagiert wird.

Die wichtigsten Punkte

  • Wenn eine Aufgabe oder eine Aufgabengruppe eine Ausnahme auslöst, wird diese Ausnahme von der Runtime gespeichert und an den Kontext gemarshallt, der wartet, bis die Aufgabe oder Aufgabengruppe beendet wird.

  • Schließen Sie nach Möglichkeit jeden Aufruf zur Parallelität::task::get und parallelcurrency::task::wait mit einem try/catch Block ein, um Fehler zu behandeln, von denen Sie wiederherstellen können. Die Runtime beendet die App, wenn eine Aufgabe eine Ausnahme auslöst und diese Ausnahme nicht durch die Aufgabe, eine ihrer Fortsetzungen oder die Haupt-App abgefangen wird.

  • Eine aufgabenbasierte Fortsetzung wird immer ausgeführt. Dabei ist unerheblich, ob die Vorgängeraufgabe erfolgreich abgeschlossen wurde, eine Ausnahme ausgelöst hat oder abgebrochen wurde. Eine wertbasierte Fortsetzung wird nicht ausgeführt, wenn die Vorgängeraufgabe eine Ausnahme auslöst oder abgebrochen wird.

  • Da aufgabenbasierte Fortsetzungen immer ausgeführt werden, erwägen Sie, am Ende der Fortsetzungskette eine aufgabenbasierte Fortsetzung hinzuzufügen. Damit kann sichergestellt werden, dass der Code alle Ausnahmen berücksichtigt.

  • Die Laufzeit löst Parallelität::task_canceled aus, wenn Sie "concurrency::task::get" aufrufen und diese Aufgabe abgebrochen wird.

  • Die Runtime verwaltet keine Ausnahmen für einfache Aufgaben und Agents.

In diesem Dokument

Aufgaben und Fortsetzungen

In diesem Abschnitt wird beschrieben, wie die Laufzeit Ausnahmen verarbeitet, die durch Parallelität::Taskobjekte und deren Fortsetzungen ausgelöst werden. Weitere Informationen zum Aufgaben- und Fortsetzungsmodell finden Sie unter Task Parallelism.

Wenn Sie eine Ausnahme im Textkörper einer Arbeitsfunktion auslösen, die Sie an ein task Objekt übergeben, speichert die Laufzeit diese Ausnahme und marshallt sie in den Kontext, der Parallelität::task::get oder concurrency::task::wait aufruft. Der Dokumentaufgabenparallelismus beschreibt aufgabenbasierte und wertbasierte Fortsetzungen, aber um zusammenzufassen, verwendet eine wertbasierte Fortsetzung einen Parameter vom TypT, und eine aufgabenbasierte Fortsetzung verwendet einen Parameter vom Typ task<T>. Wenn eine Aufgabe, die ausgelöst wird, über eine oder mehrere wertbasierte Fortsetzungen verfügt, wird die Ausführung dieser Fortsetzungen nicht geplant. Dieses Verhalten wird im folgenden Beispiel veranschaulicht:

// eh-task.cpp
// compile with: /EHsc
#include <ppltasks.h>
#include <iostream>

using namespace concurrency;
using namespace std;

int wmain()
{
    wcout << L"Running a task..." << endl;
    // Create a task that throws.
    auto t = create_task([]
    {
        throw exception();
    });
    
    // Create a continuation that prints its input value.
    auto continuation = t.then([]
    {
        // We do not expect this task to run because
        // the antecedent task threw.
        wcout << L"In continuation task..." << endl;
    });

    // Wait for the continuation to finish and handle any 
    // error that occurs.
    try
    {
        wcout << L"Waiting for tasks to finish..." << endl;
        continuation.wait();

        // Alternatively, call get() to produce the same result.
        //continuation.get();
    }
    catch (const exception& e)
    {
        wcout << L"Caught exception." << endl;
    }
}
/* Output:
    Running a task...
    Waiting for tasks to finish...
    Caught exception.
*/

Eine aufgabenbasierte Fortsetzung ermöglicht es, jede Ausnahme zu behandeln, die von der Vorgängeraufgabe ausgelöst wird. Eine aufgabenbasierte Fortsetzung wird immer ausgeführt. Dabei ist unerheblich, ob die Aufgabe erfolgreich abgeschlossen wurde, eine Ausnahme ausgelöst hat oder abgebrochen wurde. Wenn eine Aufgabe eine Ausnahme auslöst, wird die Ausführung ihrer aufgabenbasierten Fortsetzungen geplant. Im folgenden Beispiel wird eine Aufgabe dargestellt, die immer ausgelöst wird. Die Aufgabe verfügt über zwei Fortsetzungen: eine ist wertbasiert und die andere aufgabenbasiert. Die aufgabenbasierte Ausnahme wird immer ausgeführt und kann daher die Ausnahme abfangen, die von der Vorgängeraufgabe ausgelöst wird. Wenn das Beispiel darauf wartet, dass beide Fortsetzungen beendet werden, wird die Ausnahme erneut ausgelöst, da die Aufgabenausnahme immer ausgelöst wird, wenn task::get oder task::wait aufgerufen wird.

// eh-continuations.cpp
// compile with: /EHsc
#include <ppltasks.h>
#include <iostream>

using namespace concurrency;
using namespace std;

int wmain()
{    
    wcout << L"Running a task..." << endl;
    // Create a task that throws.
    auto t = create_task([]() -> int
    {
        throw exception();
        return 42;
    });

    //
    // Attach two continuations to the task. The first continuation is  
    // value-based; the second is task-based.

    // Value-based continuation.
    auto c1 = t.then([](int n)
    {
        // We don't expect to get here because the antecedent 
        // task always throws.
        wcout << L"Received " << n << L'.' << endl;
    });

    // Task-based continuation.
    auto c2 = t.then([](task<int> previousTask)
    {
        // We do expect to get here because task-based continuations
        // are scheduled even when the antecedent task throws.
        try
        {
            wcout << L"Received " << previousTask.get() << L'.' << endl;
        }
        catch (const exception& e)
        {
            wcout << L"Caught exception from previous task." << endl;
        }
    });

    // Wait for the continuations to finish.
    try
    {
        wcout << L"Waiting for tasks to finish..." << endl;
        (c1 && c2).wait();
    }
    catch (const exception& e)
    {
        wcout << L"Caught exception while waiting for all tasks to finish." << endl;
    }
}
/* Output:
    Running a task...
    Waiting for tasks to finish...
    Caught exception from previous task.
    Caught exception while waiting for all tasks to finish.
*/

Es wird empfohlen, aufgabenbasierte Fortsetzungen zu verwenden, um Ausnahmen abzufangen, die Sie behandeln können. Da aufgabenbasierte Fortsetzungen immer ausgeführt werden, erwägen Sie, am Ende der Fortsetzungskette eine aufgabenbasierte Fortsetzung hinzuzufügen. Damit kann sichergestellt werden, dass der Code alle Ausnahmen berücksichtigt. Im folgenden Beispiel wird eine grundlegende wertbasierte Fortsetzungskette dargestellt. Die dritte Aufgabe in der Kette wird ausgelöst und daher werden alle folgenden wertbasierten Fortsetzungen nicht ausgeführt. Allerdings ist die endgültige Fortsetzung aufgabenbasiert und wird daher immer ausgeführt. Diese letzte Fortsetzung behandelt die Ausnahme, die von der dritten Aufgabe ausgelöst wird.

Es wird empfohlen, die spezifischsten Ausnahmen möglichst abzufangen. Sie können diese endgültige aufgabenbasierte Fortsetzung weglassen, wenn Sie keine spezifischen Ausnahmen zum Abfangen haben. Alle Ausnahmen werden nicht behandelt und können die App beenden.

// eh-task-chain.cpp
// compile with: /EHsc
#include <ppltasks.h>
#include <iostream>

using namespace concurrency;
using namespace std;

int wmain()
{
    int n = 1;
    create_task([n]
    {
        wcout << L"In first task. n = ";
        wcout << n << endl;
        
        return n * 2;

    }).then([](int n)
    {
        wcout << L"In second task. n = ";
        wcout << n << endl;

        return n * 2;

    }).then([](int n)
    {
        wcout << L"In third task. n = ";
        wcout << n << endl;

        // This task throws.
        throw exception();
        // Not reached.
        return n * 2;

    }).then([](int n)
    {
        // This continuation is not run because the previous task throws.
        wcout << L"In fourth task. n = ";
        wcout << n << endl;

        return n * 2;

    }).then([](task<int> previousTask)
    {
        // This continuation is run because it is task-based.
        try
        {
            // The call to task::get rethrows the exception.
            wcout << L"In final task. result = ";
            wcout << previousTask.get() << endl;
        }
        catch (const exception&)
        {
            wcout << L"<exception>" << endl;
        }
    }).wait();
}
/* Output:
    In first task. n = 1
    In second task. n = 2
    In third task. n = 4
    In final task. result = <exception>
*/

Tipp

Sie können die Parallelität::task_completion_event::set_exception-Methode verwenden, um eine Ausnahme einem Vorgangsabschlussereignis zuzuordnen. Im Dokument Task Parallelism wird die Parallelität::task_completion_event Klasse ausführlicher beschrieben.

concurrency::task_canceled ist ein wichtiger Laufzeit-Ausnahmetyp, der tasksich auf . Die Runtime löst task_canceled aus, wenn Sie task::get aufrufen und diese Aufgabe abgebrochen wird. (Umgekehrt task::wait wird task_status::canceled zurückgegeben und nicht ausgelöst.) Sie können diese Ausnahme aus einer aufgabenbasierten Fortsetzung oder beim Aufrufen task::getabfangen und behandeln. Weitere Informationen zum Abbruch von Vorgängen finden Sie unter "Abbruch" in der PPL.

Achtung

Lösen Sie nie task_canceled in Ihrem Code aus. Rufen Sie stattdessen Parallelität::cancel_current_task auf .

Die Runtime beendet die App, wenn eine Aufgabe eine Ausnahme auslöst und diese Ausnahme nicht durch die Aufgabe, eine ihrer Fortsetzungen oder die Haupt-App abgefangen wird. Wenn die Anwendung abstürzt, können Sie Visual Studio so konfigurieren, dass eine Unterbrechung erfolgt, wenn C++-Ausnahmen ausgelöst werden. Nachdem Sie die Position des Ausnahmefehlers ermittelt haben, verwenden Sie eine aufgabenbasierte Fortsetzung, um ihn zu beheben.

Im Abschnitt "Ausnahmen", die von der Runtime in diesem Dokument ausgelöst werden, wird beschrieben, wie Sie mit Laufzeit ausnahmen ausführlicher arbeiten.

[Nach oben]

Aufgabengruppen und parallele Algorithmen

In diesem Abschnitt wird beschrieben, wie die Runtime Ausnahmen behandelt, die von Aufgabengruppen ausgelöst werden. Dieser Abschnitt gilt auch für parallele Algorithmen wie concurrency::p arallel_for, da diese Algorithmen auf Aufgabengruppen aufbauen.

Achtung

Es ist wichtig, dass Sie die Auswirkungen von Ausnahmen auf abhängige Aufgaben verstehen. Empfohlene Methoden zum Verwenden der Ausnahmebehandlung mit Aufgaben oder parallelen Algorithmen finden Sie im Abschnitt "Grundlegendes zur Abbruch- und Ausnahmebehandlung von Auswirkungen auf die Objektvernichtung " im Thema "Bewährte Methoden" im Thema "Parallel Patterns Library".

Weitere Informationen zu Aufgabengruppen finden Sie unter Task Parallelism. Weitere Informationen zu parallelen Algorithmen finden Sie unter Parallel-Algorithmen.

Wenn Sie eine Ausnahme im Textkörper einer Arbeitsfunktion auslösen, die Sie an eine Parallelität::task_group oder ein Parallelitätsobjekt übergeben, speichert die Laufzeit diese Ausnahme und marshallt sie in den Kontext, der concurrency::task_group::wait, concurrency::structured_task_group::wait, concurrency::wait, concurr structured_task_group ency::task_group::run_and_wait oder Concurrency:: structured_task_group::run_and_wait. 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.

Im folgenden Beispiel wird die grundlegende Struktur einer Arbeitsfunktion dargestellt, die eine Ausnahme auslöst. Im Beispiel werden die Werte von zwei task_group-Objekten mithilfe eines point-Objekts parallel ausgegeben. Die print_point-Arbeitsfunktion gibt die Werte eines point-Objekts an der Konsole aus. Die Arbeitsfunktion löst eine Ausnahme aus, wenn der Eingabewert NULL ist. Diese Ausnahme wird von der Runtime gespeichert und an den Kontext gemarshallt, der task_group::wait aufruft.

// eh-task-group.cpp
// compile with: /EHsc
#include <ppl.h>
#include <iostream>
#include <sstream>

using namespace concurrency;
using namespace std;

// Defines a basic point with X and Y coordinates.
struct point
{
   int X;
   int Y;
};

// Prints the provided point object to the console.
void print_point(point* pt)
{
   // Throw an exception if the value is NULL.
   if (pt == NULL)
   {
      throw exception("point is NULL.");
   }

   // Otherwise, print the values of the point.
   wstringstream ss;
   ss << L"X = " << pt->X << L", Y = " << pt->Y << endl;
   wcout << ss.str();
}

int wmain()
{
   // Create a few point objects.
   point pt = {15, 30};
   point* pt1 = &pt;
   point* pt2 = NULL;

   // Use a task group to print the values of the points.
   task_group tasks;

   tasks.run([&] {
      print_point(pt1);
   });

   tasks.run([&] {
      print_point(pt2);
   });

   // Wait for the tasks to finish. If any task throws an exception,
   // the runtime marshals it to the call to wait.
   try
   {
      tasks.wait();
   }
   catch (const exception& e)
   {
      wcerr << L"Caught exception: " << e.what() << endl;
   }
}

Folgende Ergebnisse werden zurückgegeben:

X = 15, Y = 30Caught exception: point is NULL.

Ein vollständiges Beispiel, das die Ausnahmebehandlung in einer Aufgabengruppe verwendet, finden Sie unter How to: Use Exception Handling to Break from a Parallel Loop.

[Nach oben]

Ausnahmen, die von der Runtime ausgelöst werden

Eine Ausnahme kann von einem Aufruf der Runtime ausgelöst werden. Die meisten Ausnahmetypen, mit Ausnahme der Parallelität::task_canceled und Parallelität::operation_timed_out, geben einen Programmierfehler an. Diese Fehler sind in der Regel nicht behebbar und dürfen daher durch Anwendungscode weder abgefangen noch behandelt werden. Es wird empfohlen, bei der Diagnose von Programmierfehlern nur nicht behebbare Fehler im Anwendungscode abzufangen oder zu behandeln. Die von der Runtime definierten Ausnahmetypen zu kennen, erleichtert jedoch die Diagnose von Programmierfehlern.

Der Mechanismus für die Ausnahmenbehandlung ist bei Ausnahmen, die durch die Runtime ausgelöst werden, derselbe wie bei Ausnahmen, der durch Arbeitsfunktionen ausgelöst werden. Die Parallelitätsfunktion::receive löst z. B. ausoperation_timed_out, wenn sie keine Nachricht im angegebenen Zeitraum empfängt. Wenn receive eine Ausnahme in einer Arbeitsfunktion auslöst, die an eine Aufgabengruppe übergeben wird, wird diese Ausnahme von der Runtime gespeichert und an den Kontext gemarshallt, der task_group::wait, structured_task_group::wait, task_group::run_and_wait oder structured_task_group::run_and_wait aufruft.

Im folgenden Beispiel wird der Parallelitätsalgorithmus::p arallel_invoke verwendet, um zwei Aufgaben parallel auszuführen. Die erste Aufgabe wartet fünf Sekunden und sendet dann eine Nachricht an einen Nachrichtenpuffer. Die zweite Aufgabe wartet mithilfe der receive-Funktion drei Sekunden auf eine Nachricht vom selben Nachrichtenpuffer. Die receive-Funktion löst die operation_timed_out-Ausnahme aus, wenn die Nachricht nicht im angegebenen Zeitraum empfangen wird.

// eh-time-out.cpp
// compile with: /EHsc
#include <agents.h>
#include <ppl.h>
#include <iostream>

using namespace concurrency;
using namespace std;

int wmain()
{
   single_assignment<int> buffer;
   int result;

   try
   {
      // Run two tasks in parallel.
      parallel_invoke(
         // This task waits 5 seconds and then sends a message to 
         // the message buffer.
         [&] {
            wait(5000); 
            send(buffer, 42);
         },
         // This task waits 3 seconds to receive a message.
         // The receive function throws operation_timed_out if it does 
         // not receive a message in the specified time period.
         [&] {
            result = receive(buffer, 3000);
         }
      );

      // Print the result.
      wcout << L"The result is " << result << endl;
   }
   catch (operation_timed_out&)
   {
      wcout << L"The operation timed out." << endl;
   }
}

Folgende Ergebnisse werden zurückgegeben:

The operation timed out.

Um sicherzustellen, dass die Anwendung ordnungsgemäß beendet wird, muss der Code beim Aufrufen der Runtime Ausnahmen behandeln. Behandeln Sie auch Ausnahmen, wenn Sie externen Code wie etwa die Bibliothek eines Drittanbieters aufrufen, der die Concurrency Runtime verwendet.

[Nach oben]

Mehrere Ausnahmen

Wenn eine Aufgabe oder paralleler Algorithmus mehrere Ausnahmen empfängt, wird nur eine dieser Ausnahmen von der Runtime an den aufrufenden Kontext gemarshallt. Dabei kann nicht vorhergesagt werden, welche Ausnahme von der Runtime gemarshallt wird.

Im folgenden Beispiel werden mithilfe des parallel_for-Algorithmus Zahlen an der Konsole ausgegeben. Es wird eine Ausnahme ausgegeben, wenn der Eingabewert kleiner als ein Mindestwert oder größer als ein Maximalwert ist. In diesem Beispiel können mehrere Arbeitsfunktionen eine Ausnahme auslösen.

// eh-multiple.cpp
// compile with: /EHsc
#include <ppl.h>
#include <iostream>
#include <sstream>

using namespace concurrency;
using namespace std;

int wmain()
{
   const int min = 0;
   const int max = 10;
   
   // Print values in a parallel_for loop. Use a try-catch block to 
   // handle any exceptions that occur in the loop.
   try
   {
      parallel_for(-5, 20, [min,max](int i)
      {
         // Throw an exeception if the input value is less than the 
         // minimum or greater than the maximum.

         // Otherwise, print the value to the console.

         if (i < min)
         {
            stringstream ss;
            ss << i << ": the value is less than the minimum.";
            throw exception(ss.str().c_str());
         }
         else if (i > max)
         {
            stringstream ss;
            ss << i << ": the value is greater than than the maximum.";
            throw exception(ss.str().c_str());
         }
         else
         {
            wstringstream ss;
            ss << i << endl;
            wcout << ss.str();
         }
      });
   }
   catch (exception& e)
   {
      // Print the error to the console.
      wcerr << L"Caught exception: " << e.what() << endl;
   }  
}

Nachfolgend wird eine Beispielausgabe für dieses Beispiel angezeigt.

8293104567Caught exception: -5: the value is less than the minimum.

[Nach oben]

Abbruch

Nicht alle Ausnahmen geben einen Fehler an. Ein Suchalgorithmus kann beispielsweise mithilfe der Ausnahmenbehandlung die zugehörige Aufgabe beenden, sobald das Ergebnis gefunden ist. Weitere Informationen zur Verwendung von Abbruchmechanismen in Ihrem Code finden Sie unter "Abbruch" in der PPL.

[Nach oben]

Einfache Aufgaben

Ein einfacher Vorgang ist ein Vorgang, den Sie direkt aus einem Parallelitätsobjekt::Scheduler planen. Einfache Aufgaben erfordern einen geringeren Aufwand als gewöhnliche Aufgaben. Die Runtime fängt jedoch keine Ausnahmen ab, die von einfachen Aufgaben ausgelöst werden. Stattdessen wird die Ausnahme vom Handler für nicht behandelte Ausnahmen abgefangen, der den Prozess standardmäßig beendet. Verwenden Sie daher in der Anwendung einen entsprechenden Fehlerbehandlungsmechanismus. Weitere Informationen zu einfachen Vorgängen finden Sie unter "Task Scheduler".

[Nach oben]

Asynchrone Agents

Die Runtime verwaltet wie bei einfachen Aufgaben auch keine Ausnahmen, die von asynchronen Agents ausgelöst werden.

Das folgende Beispiel zeigt eine Möglichkeit zum Behandeln von Ausnahmen in einer Klasse, die von "concurrency::agent" abgeleitet ist. In diesem Beispiel wird die points_agent-Klasse definiert. Die points_agent::run-Methode liest point-Objekte aus dem Nachrichtenpuffer und gibt sie an der Konsole aus. Die run-Methode löst beim Empfang eines NULL-Zeigers eine Ausnahme aus.

Die run Methode umgibt alle Arbeiten in einem try-catch Block. Die Ausnahme wird vom catch-Block in einem Nachrichtenpuffer gespeichert. Die Anwendung überprüft, ob im Agent ein Fehler aufgetreten ist. Hierzu wird dieser Puffer nach Abschluss des Agents gelesen.

// eh-agents.cpp
// compile with: /EHsc
#include <agents.h>
#include <iostream>

using namespace concurrency;
using namespace std;

// Defines a point with x and y coordinates.
struct point
{
   int X;
   int Y;
};

// Informs the agent to end processing.
point sentinel = {0,0};

// An agent that prints point objects to the console.
class point_agent : public agent
{
public:
   explicit point_agent(unbounded_buffer<point*>& points)
      : _points(points)
   { 
   }

   // Retrieves any exception that occurred in the agent.
   bool get_error(exception& e)
   {
      return try_receive(_error, e);
   }

protected:
   // Performs the work of the agent.
   void run()
   {
      // Perform processing in a try block.
      try
      {
         // Read from the buffer until we reach the sentinel value.
         while (true)
         {
            // Read a value from the message buffer.
            point* r = receive(_points);

            // In this example, it is an error to receive a 
            // NULL point pointer. In this case, throw an exception.
            if (r == NULL)
            {
               throw exception("point must not be NULL");
            }
            // Break from the loop if we receive the 
            // sentinel value.
            else if (r == &sentinel)
            {
               break;
            }
            // Otherwise, do something with the point.
            else
            {
               // Print the point to the console.
               wcout << L"X: " << r->X << L" Y: " << r->Y << endl;
            }
         }
      }
      // Store the error in the message buffer.
      catch (exception& e)
      {
         send(_error, e);
      }

      // Set the agent status to done.
      done();
   }

private:
   // A message buffer that receives point objects.
   unbounded_buffer<point*>& _points;

   // A message buffer that stores error information.
   single_assignment<exception> _error;
};

int wmain()
{  
   // Create a message buffer so that we can communicate with
   // the agent.
   unbounded_buffer<point*> buffer;

   // Create and start a point_agent object.
   point_agent a(buffer);
   a.start();

   // Send several points to the agent.
   point r1 = {10, 20};
   point r2 = {20, 30};
   point r3 = {30, 40};

   send(buffer, &r1);
   send(buffer, &r2);
   // To illustrate exception handling, send the NULL pointer to the agent.
   send(buffer, reinterpret_cast<point*>(NULL));
   send(buffer, &r3);
   send(buffer, &sentinel);

   // Wait for the agent to finish.
   agent::wait(&a);
  
   // Check whether the agent encountered an error.
   exception e;
   if (a.get_error(e))
   {
      cout << "error occurred in agent: " << e.what() << endl;
   }
   
   // Print out agent status.
   wcout << L"the status of the agent is: ";
   switch (a.status())
   {
   case agent_created:
      wcout << L"created";
      break;
   case agent_runnable:
      wcout << L"runnable";
      break;
   case agent_started:
      wcout << L"started";
      break;
   case agent_done:
      wcout << L"done";
      break;
   case agent_canceled:
      wcout << L"canceled";
      break;
   default:
      wcout << L"unknown";
      break;
   }
   wcout << endl;
}

Folgende Ergebnisse werden zurückgegeben:

X: 10 Y: 20
X: 20 Y: 30
error occurred in agent: point must not be NULL
the status of the agent is: done

Da der try-catch Block außerhalb der while Schleife vorhanden ist, beendet der Agent die Verarbeitung, wenn der erste Fehler auftritt. Wenn sich der try-catch Block innerhalb der while Schleife befindet, wird der Agent fortgesetzt, nachdem ein Fehler aufgetreten ist.

In diesem Beispiel werden Ausnahmen in einem Nachrichtenpuffer gespeichert, damit eine andere Komponente den Agent beim Ausführen auf Fehler überwachen kann. In diesem Beispiel wird ein Parallelitätsobjekt::single_assignment verwendet, um den Fehler zu speichern. Wenn ein Agent mehrere Ausnahmen behandelt speichert die single_assignment-Klasse nur die erste Nachricht, die an sie übergeben wird. Verwenden Sie die Parallelität::overwrite_buffer Klasse, um nur die letzte Ausnahme zu speichern. Verwenden Sie die Parallelität::unbounded_buffer Klasse, um alle Ausnahmen zu speichern. Weitere Informationen zu diesen Nachrichtenblöcken finden Sie unter "Asynchrone Nachrichtenblöcke".

Weitere Informationen zu asynchronen Agents finden Sie unter "Asynchrone Agents".

[Nach oben]

Zusammenfassung

[Nach oben]

Siehe auch

Concurrency Runtime
Task-Parallelität
Parallele Algorithmen
Abbruch in der PPL
Aufgabenplanung
Asynchrone Agents