Freigeben über


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.

Wesentliche 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.

  • Umschließen Sie nach Möglichkeit jeden Aufruf von concurrency::task::get und concurrency::task::wait mit einem try/catch-Block, um Fehler zu behandeln, die Sie beheben 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 Runtime löst concurrency::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

  • Aufgabengruppen und parallele Algorithmen

  • Von der Runtime ausgelöste Ausnahmen

  • Mehrere Ausnahmen

  • Abbruch

  • Einfache Aufgaben

  • Asynchrone Agents

Aufgaben und Fortsetzungen

Dieser Abschnitt beschreibt, wie die Runtime Ausnahmen behandelt, die von concurrency::task-Objekten und deren Fortsetzungen ausgelöst werden. Weitere Informationen zu dieser Aufgabe und diesem Fortsetzungsmodell finden Sie unter Aufgabenparallelität (Concurrency Runtime).

Wenn Sie im Text einer Arbeitsfunktion, die Sie an ein task-Objekt übergeben, eine Ausnahme auslösen, speichert die Runtime diese Ausnahme und marshallt sie an den Kontext, der concurrency::task::get oder concurrency::task::wait aufruft. Das Dokument Aufgabenparallelität (Concurrency Runtime) beschreibt aufgabenbasierte Fortsetzungen und wertbasierte Fortsetzungen im Vergleich. Zusammenfassend ausgedrückt, akzeptiert eine wertbasierte Fortsetzung einen Parameter vom Typ T und eine aufgabenbasierte Fortsetzung 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 können 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 abzufangen 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 value-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 concurrency::task_completion_event::set_exception-Methode verwenden, um einer Ausnahme ein Aufgabenabschlussereignis zuzuordnen.Im Dokument Aufgabenparallelität (Concurrency Runtime) wird die concurrency::task_completion_event-Klasse ausführlich beschrieben.

concurrency::task_canceled ist ein wichtiger Runtime-Ausnahmetyp, der mit task verknüpft ist. Die Runtime löst task_canceled aus, wenn Sie task::get aufrufen und diese Aufgabe abgebrochen wird. (Umgekehrt gibt task::wait task_status::canceled zurück und wird nicht ausgelöst.) Sie können diese Ausnahme von einer aufgabenbasierten Fortsetzung oder beim Aufrufen von task::get abfangen und behandeln. Weitere Informationen zum Aufgabenabbruch finden Sie unter Abbruch in der PPL.

Warnung

Lösen Sie nie task_canceled in Ihrem Code aus.Rufen Sie stattdessen concurrency::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 Von der Runtime ausgelöste Ausnahmen in diesem Dokument wird ausführlicher beschrieben, wie Runtime-Ausnahmen funktionieren.

[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, z. B. concurrency::parallel_for, da diese Algorithmen auf Aufgabengruppen aufbauen.

Warnung

Es ist wichtig, dass Sie die Auswirkungen von Ausnahmen auf abhängige Aufgaben verstehen.Empfohlene Vorgehensweisen zum Verwenden der Ausnahmebehandlung bei Aufgaben oder parallelen Algorithmen finden Sie im entsprechenden Abschnitt der Parallel Patterns Library unter Informieren Sie sich über die Auswirkungen von Abbruch und Ausnahmebehandlung auf die Zerstörung von Objekten.

Weitere Informationen zu Aufgabengruppen finden Sie unter Aufgabenparallelität (Concurrency Runtime). Weitere Informationen zu parallelen Algorithmen finden Sie unter Parallele Algorithmen.

Wenn im Text einer Arbeitsfunktion, die an ein concurrency::task_group-Objekt oder an ein concurrency::structured_task_group-Objekt übergeben wird, eine Ausnahme ausgelöst wird, wird diese Ausnahme von der Runtime gespeichert und an den Kontext gemarshallt, der concurrency::task_group::wait, concurrency::structured_task_group::wait, concurrency::task_group::run_and_wait oder concurrency::structured_task_group::run_and_wait aufruft. 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 point-Objekten mithilfe eines task_group-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:

  

Ein umfassendes Beispiel für die Verwendung der Ausnahmebehandlung in einer Aufgabengruppe finden Sie unter Gewusst wie: Verwenden der Ausnahmebehandlung zum Verlassen einer Parallel-Schleife.

[Nach oben]

Von der Runtime ausgelöste Ausnahmen

Eine Ausnahme kann von einem Aufruf der Runtime ausgelöst werden. Die meisten Ausnahmetypen, außer concurrency::task_canceled und concurrency::operation_timed_out, weisen auf einen Programmierfehler hin. 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 concurrency::receive-Funktion löst beispielsweise eine operation_timed_out-Ausnahme aus, wenn eine Nachricht nicht im angegebenen Zeitraum empfangen wird. 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 werden zwei Aufgaben mithilfe des concurrency::parallel_invoke-Algorithmus parallel ausgeführt. 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:

  

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.

  

[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 zum Verwenden von Abbruchmechanismen im Code finden Sie unter Abbruch in der PPL.

[Nach oben]

Einfache Aufgaben

Eine einfache Aufgabe ist eine Aufgabe, die Sie direkt über ein concurrency::Scheduler-Objekt 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 Aufgaben finden Sie unter Taskplaner (Concurrency Runtime).

[Nach oben]

Asynchrone Agents

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

Im folgenden Beispiel wird eine Möglichkeit für die Behandlung von Ausnahmen in einer Klasse dargestellt, die von concurrency::agent abgeleitet wird. 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 schließt alle Arbeiten in einen try-catch-Block ein. 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:

  

Da sich der try-catch-Block außerhalb der while-Schleife befindet, beendet der Agent die Verarbeitung, sobald der erste Fehler auftritt. Wenn sich der try-catch-Block innerhalb der while-Schleife befände, würde der Agent die Verarbeitung nach dem Auftreten eines Fehlers fortsetzen.

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 der Fehler mithilfe eines concurrency::single_assignment-Objekts gespeichert. Wenn ein Agent mehrere Ausnahmen behandelt speichert die single_assignment-Klasse nur die erste Nachricht, die an sie übergeben wird. Wenn nur die letzte Ausnahme gespeichert werden soll, verwenden Sie die concurrency::overwrite_buffer-Klasse. Um alle Ausnahmen zu speichern, verwenden Sie die concurrency::unbounded_buffer-Klasse. 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

Konzepte

Concurrency Runtime

Aufgabenparallelität (Concurrency Runtime)

Parallele Algorithmen

Abbruch in der PPL

Taskplaner (Concurrency Runtime)

Asynchrone Agents