Dieser Artikel wurde maschinell übersetzt. Bewegen Sie den Mauszeiger über die Sätze im Artikel, um den Originaltext anzuzeigen. Weitere Informationen
Übersetzung
Original
Dieser Artikel wurde noch nicht bewertet - Dieses Thema bewerten.

Ausnahmebehandlung (Task Parallel Library)

Nicht behandelte Ausnahmen, die von innerhalb einer Aufgabe ausgeführtem Benutzercode ausgelöst werden, werden zurück zum Verbindungsthread geleitet. Hiervon ausgenommen sind bestimmte Szenarios, die weiter unten in diesem Thema beschrieben werden. Ausnahmen werden weitergegeben, wenn Sie die statische oder instanzbasierte Task.Wait-Methode oder Task<TResult>.Wait-Methode verwenden. Zur Behandlung dieser Ausnahmen schließen Sie den Aufruf in eine try-catch-Anweisung ein. Wenn eine Aufgabe das übergeordnete Element angefügter untergeordneter Aufgaben ist oder wenn Sie auf mehrere Aufgaben warten, können mehrere Ausnahmen ausgelöst werden. Um alle Ausnahmen zurück an den aufrufenden Thread zu leiten, schließt die Aufgabeninfrastruktur diese in eine AggregateException-Instanz ein. AggregateException InnerExceptions verfügt über eine Eigenschaft, die aufgelistet werden kann, um alle ursprünglichen Ausnahmen zu überprüfen, die ausgelöst wurden und (oder nicht behandelt) jedes einzeln behandelt. Auch wenn nur eine Ausnahme ausgelöst wurde, wird diese in eine AggregateException eingeschlossen.


var task1 = Task.Factory.StartNew(() =>
{
    throw new MyCustomException("I'm bad, but not too bad!");
});

try
{
    task1.Wait();
}
catch (AggregateException ae)
{
    // Assume we know what's going on with this particular exception.
    // Rethrow anything else. AggregateException.Handle provides
    // another way to express this. See later example.
    foreach (var e in ae.InnerExceptions)
    {
        if (e is MyCustomException)
        {
            Console.WriteLine(e.Message);
        }
        else
        {
            throw;
        }
    }

}


Unbehandeltes Ausnahmen vermeiden Sie, indem Sie nur die AggregateException erfassen und die inneren Ausnahmen nicht beachten. Hiervon wird jedoch abgeraten, da dies dem Erfassen des Basisausnahmetyps in nicht parallelen Szenarios entspricht. Wenn Sie eine Ausnahme erfassen, ohne Maßnahmen zu deren Behandlung zu ergreifen, weist das Programm ggf. einen unbestimmten Zustand auf.

Wenn Sie nicht auf eine Aufgabe warten, die eine Ausnahme weitergibt, oder auf deren Exception-Eigenschaft zugreifen, wird die Ausnahme entsprechend der .NET-Ausnahmerichtlinie eskaliert, sofern die Aufgabe der Garbage Collection unterliegt.

Wenn Ausnahmen mittels Bubbling wieder an den Verbindungsthread übergeben werden können, ist es möglich, dass eine Aufgabe nach dem Auslösen der Ausnahme weiterhin einige Elemente verarbeitet.

Hinweis Hinweis

Wenn "Nur eigenen Code" aktiviert ist, unterbricht Visual Studio die Ausführung in einigen Fällen in der Zeile, die die Ausnahme auslöst, und eine Fehlermeldung zu einer nicht vom Benutzercode behandelten Ausnahme wird angezeigt. Dieser Fehler hat keine Auswirkungen. Sie können F5 drücken, um den Vorgang fortzusetzen. In diesem Fall wird das in den folgenden Beispielen veranschaulichte Ausnahmebehandlungsverhalten angewendet. Um zu verhindern, dass Visual Studio die Ausführung beim ersten Fehler unterbricht, deaktivieren Sie das Kontrollkästchen "Nur eigenen Code" unter Extras > Optionen > Debugging > Allgemein.

Wenn eine Aufgabe über eine angefügte untergeordnete Aufgabe verfügt, die eine Ausnahme auslöst, wird diese Ausnahme in AggregateException eingeschlossen, bevor sie an die übergeordnete Aufgabe weitergegeben wird, die diese Ausnahme in eine eigene AggregateException einschließt und sie anschließend an den aufrufenden Thread zurückgibt. In solchen Fällen die InnerExceptions-Eigenschaft AggregateException, die bei Task.Wait abgefangen wird, oder Task<TResult>.Wait oder WaitAny oder WaitAll-Methode eine oder mehrere Instanzen AggregateException enthält, nicht die ursprünglichen Ausnahmen, die den Fehler verursacht haben. Um eine Iteration geschachtelter AggregateExceptions zu vermeiden, können Sie mit der - Flatten-Methode alle geschachtelten AggregateExceptions entfernen, sodass die AggregateException.InnerExceptions-Eigenschaft die ursprünglichen Ausnahmen enthält. Im folgenden Beispiel werden geschachtelte AggregateException-Instanzen vereinfacht und in nur einen Schleife behandelt.


// task1 will throw an AE inside an AE inside an AE
var task1 = Task.Factory.StartNew(() =>
{
    var child1 = Task.Factory.StartNew(() =>
        {
            var child2 = Task.Factory.StartNew(() =>
            {
                throw new MyCustomException("Attached child2 faulted.");
            },
            TaskCreationOptions.AttachedToParent);

            // Uncomment this line to see the exception rethrown.
            // throw new MyCustomException("Attached child1 faulted.");
        },
        TaskCreationOptions.AttachedToParent);
});

try
{
    task1.Wait();
}
catch (AggregateException ae)
{

    foreach (var e in ae.Flatten().InnerExceptions)
    {
        if (e is MyCustomException)
        {
            // Recover from the exception. Here we just
            // print the message for demonstration purposes.
            Console.WriteLine(e.Message);
        }
        else
        {
            throw;
        }
    }
    // or ...
   // ae.Flatten().Handle((ex) => ex is MyCustomException);

}


Standardmäßig werden untergeordnete Aufgaben als getrennte Aufgaben erstellt. Von getrennten Aufgaben ausgelöste Ausnahmen müssen in der unmittelbar übergeordneten Aufgabe behandelt oder erneut ausgelöst werden. Sie werden nicht auf die gleiche Weise wie angefügte untergeordnete Aufgaben an den aufrufenden Thread zurück geleitet. Das übergeordnete Element der höchsten Ebene kann eine Ausnahme von einem getrennten untergeordneten Element manuell erneut auslösen, sodass diese in eine AggregateException eingeschlossen und an den Verbindungsthread zurück geleitet wird.


var task1 = Task.Factory.StartNew(() =>
{

    var nested1 = Task.Factory.StartNew(() =>
    {
        throw new MyCustomException("Nested task faulted.");
    });

    // Here the exception will be escalated back to joining thread.
    // We could use try/catch here to prevent that.
    nested1.Wait();

});

try
{
    task1.Wait();
}
catch (AggregateException ae)
{

    foreach (var e in ae.Flatten().InnerExceptions)
    {
        if (e is MyCustomException)
        {
            // Recover from the exception. Here we just
            // print the message for demonstration purposes.
            Console.WriteLine(e.Message);
        }
    }
}


Selbst wenn Sie mithilfe einer Fortsetzung eine Ausnahme in einer untergeordneten Aufgabe beachten, muss die Ausnahme dennoch von der übergeordneten Aufgabe beachtet werden.

Wenn Benutzercode in einer Aufgabe auf eine Abbruchanforderung reagiert, besteht das korrekte Verfahren darin, dass eine OperationCanceledException ausgelöst wird, die in dem Abbruchtoken, in dem die Anforderung übermittelt wurde, übergeben wird. Bevor die Ausnahme weitergeleitet wird, vergleicht die Aufgabeninstanz das Token in der Ausnahme mit dem Token, das beim Erstellen an sie übergeben wurde. Stimmen beide Token überein, gibt die Aufgabe eine TaskCanceledException weiter, die in die AggregateException eingeschlossen ist. Diese ist zu sehen, wenn die inneren Ausnahmen analysiert werden. Wenn der Verbindungsthread jedoch nicht auf die Aufgabe wartet, wird diese Ausnahme nicht weitergegeben. Weitere Informationen finden Sie unter Aufgabenabbruch.


var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;

var task1 = Task.Factory.StartNew(() =>
{
    CancellationToken ct = token;
    while (someCondition)
    {
        // Do some work...
        Thread.SpinWait(50000);
        ct.ThrowIfCancellationRequested();
    }
},
token);

// No waiting required.


Mit der AggregateException.Handle-Methode können Sie Ausnahmen filtern, die ohne weitere Logik als "behandelt" definiert werden können. Im Benutzerdelegaten, der an AggregateException.Handle weitergegeben wird, können Sie den Ausnahmetyp, dessen Message-Eigenschaft oder beliebige andere Informationen analysieren und ermitteln, ob die Ausnahme keine Auswirkungen zeigt. Alle Ausnahmen, für die die Delegatrückgaben false in einer neuen Instanz AggregateException erneut ausgelöst werden, nachdem AggregateException.Handle zurückgibt.

Im folgenden Codeausschnitt wird eine foreach-Schleife über die inneren Ausnahmen verwendet.


foreach (var e in ae.InnerExceptions)
{
    if (e is MyCustomException)
    {
        Console.WriteLine(e.Message);
    }
    else
    {
        throw;
    }
}


Im folgenden Codeausschnitt wird die funktional entsprechende Verwendung der Handle-Methode gezeigt.


ae.Handle((ex) =>
{
    return ex is MyCustomException;
});


Wenn eine Aufgabe mit einem Faulted-Zustand abgeschlossen wird, kann die zugehörige Exception-Eigenschaft analysiert werden, um die spezifische Ausnahme zu ermitteln, die den Fehler verursacht hat. Eine gute Möglichkeit, die Exception-Eigenschaft zu beachten, ist eine Fortsetzung, die nur bei einem Fehler in der vorausgehenden Aufgabe ausgeführt wird, wie im folgenden Beispiel gezeigt.


var task1 = Task.Factory.StartNew(() =>
{
    throw new MyCustomException("Task1 faulted.");
})
.ContinueWith((t) =>
    {
        Console.WriteLine("I have observed a {0}",
            t.Exception.InnerException.GetType().Name);
    },
    TaskContinuationOptions.OnlyOnFaulted);


In einer realen Anwendung würde der Fortsetzungsdelegat ausführliche Informationen zu der Ausnahme protokollieren und möglicherweise neue Aufgaben erzeugen, um die Ausnahme zu beheben.

In einigen Szenarien können häufig Ausnahmen ohne Auswirkungen auftreten (z. B. wenn Sie nicht vertrauenswürdige Plug-Ins hosten), und es kann schwierig sein, alle Ausnahmen manuell zu überwachen. In diesen Fällen können Sie das TaskScheduler.UnobservedTaskException-Ereignis behandeln. Mit der an den Handler übergebenen System.Threading.Tasks.UnobservedTaskExceptionEventArgs-Instanz kann verhindert werden, dass die nicht überwachte Ausnahme wieder an den Verbindungsthread übergeben wird.

Fanden Sie dies hilfreich?
(1500 verbleibende Zeichen)

Community-Beiträge

HINZUFÜGEN
Microsoft führt eine Onlineumfrage durch, um Ihre Meinung zur MSDN-Website zu erfahren. Wenn Sie sich zur Teilnahme entscheiden, wird Ihnen die Onlineumfrage angezeigt, sobald Sie die MSDN-Website verlassen.

Möchten Sie an der Umfrage teilnehmen?
© 2013 Microsoft. Alle Rechte vorbehalten.