Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Unbehandelte Ausnahmen, die von Benutzercode ausgelöst werden, der innerhalb einer Aufgabe ausgeführt wird, werden an den aufrufenden Thread weitergegeben, außer in bestimmten Szenarien, die weiter unten in diesem Thema beschrieben werden. Ausnahmen werden weitergegeben, wenn Sie eine der statischen oder Instanzmethoden Task.Wait verwenden und diese behandeln, indem Sie den Aufruf in eine try
/catch
Anweisung einschließen. 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 verteilen, schließt die Taskinfrastruktur sie in eine AggregateException Instanz um. Die AggregateException-Ausnahme verfügt über eine InnerExceptions-Eigenschaft, die aufgelistet werden kann, um alle ursprünglich ausgelösten Ausnahmen zu analysieren und jede Ausnahme einzeln zu behandeln (bzw. nicht zu behandeln). Sie können die ursprünglichen Ausnahmen auch mithilfe der AggregateException.Handle Methode behandeln.
Auch wenn nur eine Ausnahme ausgelöst wird, wird sie weiterhin in eine AggregateException Ausnahme eingeschlossen, wie im folgenden Beispiel gezeigt.
public static partial class Program
{
public static void HandleThree()
{
var task = Task.Run(
() => throw new CustomException("This exception is expected!"));
try
{
task.Wait();
}
catch (AggregateException ae)
{
foreach (var ex in ae.InnerExceptions)
{
// Handle the custom exception.
if (ex is CustomException)
{
Console.WriteLine(ex.Message);
}
// Rethrow any other exception.
else
{
throw ex;
}
}
}
}
}
// The example displays the following output:
// This exception is expected!
Imports System.Threading.Tasks
Module Example
Public Sub Main()
Dim task1 = Task.Run(Sub() Throw New CustomException("This exception is expected!"))
Try
task1.Wait()
Catch ae As AggregateException
For Each ex In ae.InnerExceptions
' Handle the custom exception.
If TypeOf ex Is CustomException Then
Console.WriteLine(ex.Message)
' Rethrow any other exception.
Else
Throw ex
End If
Next
End Try
End Sub
End Module
Class CustomException : Inherits Exception
Public Sub New(s As String)
MyBase.New(s)
End Sub
End Class
' The example displays the following output:
' This exception is expected!
Unbehandeltes Ausnahmen vermeiden Sie, indem Sie nur die AggregateException erfassen und die inneren Ausnahmen nicht beachten. Es wird jedoch empfohlen, dies nicht zu tun, da es analog zum Abfangen des Basistyps Exception in nicht parallelen Szenarien ist. Wenn Sie eine Ausnahme erfassen, ohne Maßnahmen zu deren Behandlung zu ergreifen, weist das Programm ggf. einen unbestimmten Zustand auf.
Wenn Sie die Methode nicht aufrufen möchten, um auf den Task.Wait Abschluss einer Aufgabe zu warten, können Sie auch die AggregateException Ausnahme aus der Eigenschaft der Aufgabe Exception abrufen, wie das folgende Beispiel zeigt. Weitere Informationen finden Sie im Abschnitt "Beobachten von Ausnahmen mit der Task.Exception-Eigenschaft" in diesem Thema.
public static partial class Program
{
public static void HandleFour()
{
var task = Task.Run(
() => throw new CustomException("This exception is expected!"));
while (!task.IsCompleted) { }
if (task.Status == TaskStatus.Faulted)
{
foreach (var ex in task.Exception?.InnerExceptions ?? new(Array.Empty<Exception>()))
{
// Handle the custom exception.
if (ex is CustomException)
{
Console.WriteLine(ex.Message);
}
// Rethrow any other exception.
else
{
throw ex;
}
}
}
}
}
// The example displays the following output:
// This exception is expected!
Imports System.Threading.Tasks
Module Example
Public Sub Main()
Dim task1 = Task.Run(Sub() Throw New CustomException("This exception is expected!"))
While Not task1.IsCompleted
End While
If task1.Status = TaskStatus.Faulted Then
For Each ex In task1.Exception.InnerExceptions
' Handle the custom exception.
If TypeOf ex Is CustomException Then
Console.WriteLine(ex.Message)
' Rethrow any other exception.
Else
Throw ex
End If
Next
End If
End Sub
End Module
Class CustomException : Inherits Exception
Public Sub New(s As String)
MyBase.New(s)
End Sub
End Class
' The example displays the following output:
' This exception is expected!
Vorsicht
Der vorherige Beispielcode enthält eine while
-Schleife, die die Task.IsCompleted-Eigenschaft der Aufgabe abfragt, um zu bestimmen, wann die Aufgabe abgeschlossen wurde. Dies sollte niemals im Produktionscode erfolgen, da sie sehr ineffizient ist.
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 wieder in den Verknüpfungsthread eingeblasen werden dürfen, ist es möglich, dass eine Aufgabe einige Elemente nach dem Auslösen der Ausnahme weiter verarbeitet.
Hinweis
Wenn "Just My Code" aktiviert ist, wird Visual Studio in einigen Fällen an der Zeile anhalten, die die Ausnahme auslöst, und eine Fehlermeldung mit der Meldung "Ausnahme wird nicht von Benutzercode behandelt" anzeigen. Dieser Fehler ist unbedeutend. 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.
Angefügte untergeordnete Aufgaben und geschachtelte AggregateExceptions
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 enthält die InnerExceptions-Eigenschaft der AggregateException-Ausnahme, die bei der Task.Wait, WaitAny oder WaitAll-Methode abgefangen wird, eine oder mehrere AggregateException-Instanzen, nicht die ursprünglichen Ausnahmen, die den Fehler verursacht haben. Um zu vermeiden, dass Sie über geschachtelte AggregateException Ausnahmen iterieren müssen, können Sie mit der Flatten Methode alle geschachtelten AggregateException Ausnahmen 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.
public static partial class Program
{
public static void FlattenTwo()
{
var task = Task.Factory.StartNew(() =>
{
var child = Task.Factory.StartNew(() =>
{
var grandChild = Task.Factory.StartNew(() =>
{
// This exception is nested inside three AggregateExceptions.
throw new CustomException("Attached child2 faulted.");
}, TaskCreationOptions.AttachedToParent);
// This exception is nested inside two AggregateExceptions.
throw new CustomException("Attached child1 faulted.");
}, TaskCreationOptions.AttachedToParent);
});
try
{
task.Wait();
}
catch (AggregateException ae)
{
foreach (var ex in ae.Flatten().InnerExceptions)
{
if (ex is CustomException)
{
Console.WriteLine(ex.Message);
}
else
{
throw;
}
}
}
}
}
// The example displays the following output:
// Attached child1 faulted.
// Attached child2 faulted.
Imports System.Threading.Tasks
Module Example
Public Sub Main()
Dim task1 = Task.Factory.StartNew(Sub()
Dim child1 = Task.Factory.StartNew(Sub()
Dim child2 = Task.Factory.StartNew(Sub()
Throw New CustomException("Attached child2 faulted.")
End Sub,
TaskCreationOptions.AttachedToParent)
Throw New CustomException("Attached child1 faulted.")
End Sub,
TaskCreationOptions.AttachedToParent)
End Sub)
Try
task1.Wait()
Catch ae As AggregateException
For Each ex In ae.Flatten().InnerExceptions
If TypeOf ex Is CustomException Then
Console.WriteLine(ex.Message)
Else
Throw
End If
Next
End Try
End Sub
End Module
Class CustomException : Inherits Exception
Public Sub New(s As String)
MyBase.New(s)
End Sub
End Class
' The example displays the following output:
' Attached child1 faulted.
' Attached child2 faulted.
Sie können auch die AggregateException.Flatten-Methode verwenden, um die inneren Ausnahmen von mehreren AggregateException-Instanzen erneut auszulösen, die von mehreren Aufgaben in einer einzelnen AggregateException-Instanz ausgelöst wurden, wie im folgenden Beispiel gezeigt.
public static partial class Program
{
public static void TaskExceptionTwo()
{
try
{
ExecuteTasks();
}
catch (AggregateException ae)
{
foreach (var e in ae.InnerExceptions)
{
Console.WriteLine($"{e.GetType().Name}:\n {e.Message}");
}
}
}
static void ExecuteTasks()
{
// Assume this is a user-entered String.
string path = @"C:\";
List<Task> tasks = new();
tasks.Add(Task.Run(() =>
{
// This should throw an UnauthorizedAccessException.
return Directory.GetFiles(
path, "*.txt",
SearchOption.AllDirectories);
}));
tasks.Add(Task.Run(() =>
{
if (path == @"C:\")
{
throw new ArgumentException(
"The system root is not a valid path.");
}
return new string[] { ".txt", ".dll", ".exe", ".bin", ".dat" };
}));
tasks.Add(Task.Run(() =>
{
throw new NotImplementedException(
"This operation has not been implemented.");
}));
try
{
Task.WaitAll(tasks.ToArray());
}
catch (AggregateException ae)
{
throw ae.Flatten();
}
}
}
// The example displays the following output:
// UnauthorizedAccessException:
// Access to the path 'C:\Documents and Settings' is denied.
// ArgumentException:
// The system root is not a valid path.
// NotImplementedException:
// This operation has not been implemented.
Imports System.Collections.Generic
Imports System.IO
Imports System.Threading.Tasks
Module Example
Public Sub Main()
Try
ExecuteTasks()
Catch ae As AggregateException
For Each e In ae.InnerExceptions
Console.WriteLine("{0}:{2} {1}", e.GetType().Name, e.Message,
vbCrLf)
Next
End Try
End Sub
Sub ExecuteTasks()
' Assume this is a user-entered String.
Dim path = "C:\"
Dim tasks As New List(Of Task)
tasks.Add(Task.Run(Function()
' This should throw an UnauthorizedAccessException.
Return Directory.GetFiles(path, "*.txt",
SearchOption.AllDirectories)
End Function))
tasks.Add(Task.Run(Function()
If path = "C:\" Then
Throw New ArgumentException("The system root is not a valid path.")
End If
Return {".txt", ".dll", ".exe", ".bin", ".dat"}
End Function))
tasks.Add(Task.Run(Sub()
Throw New NotImplementedException("This operation has not been implemented.")
End Sub))
Try
Task.WaitAll(tasks.ToArray)
Catch ae As AggregateException
Throw ae.Flatten()
End Try
End Sub
End Module
' The example displays the following output:
' UnauthorizedAccessException:
' Access to the path 'C:\Documents and Settings' is denied.
' ArgumentException:
' The system root is not a valid path.
' NotImplementedException:
' This operation has not been implemented.
Ausnahmen bei getrennten untergeordneten Aufgaben
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 aufrufenden Thread zurück geleitet wird.
public static partial class Program
{
public static void DetachedTwo()
{
var task = Task.Run(() =>
{
var nestedTask = Task.Run(
() => throw new CustomException("Detached child task faulted."));
// Here the exception will be escalated back to the calling thread.
// We could use try/catch here to prevent that.
nestedTask.Wait();
});
try
{
task.Wait();
}
catch (AggregateException ae)
{
foreach (var e in ae.Flatten().InnerExceptions)
{
if (e is CustomException)
{
Console.WriteLine(e.Message);
}
}
}
}
}
// The example displays the following output:
// Detached child task faulted.
Imports System.Threading.Tasks
Module Example
Public Sub Main()
Dim task1 = Task.Run(Sub()
Dim nestedTask1 = Task.Run(Sub()
Throw New CustomException("Detached child task faulted.")
End Sub)
' Here the exception will be escalated back to joining thread.
' We could use try/catch here to prevent that.
nestedTask1.Wait()
End Sub)
Try
task1.Wait()
Catch ae As AggregateException
For Each ex In ae.Flatten().InnerExceptions
If TypeOf ex Is CustomException Then
' Recover from the exception. Here we just
' print the message for demonstration purposes.
Console.WriteLine(ex.Message)
End If
Next
End Try
End Sub
End Module
Class CustomException : Inherits Exception
Public Sub New(s As String)
MyBase.New(s)
End Sub
End Class
' The example displays the following output:
' Detached child task faulted.
Selbst wenn Sie mithilfe einer Fortsetzung eine Ausnahme in einer untergeordneten Aufgabe beachten, muss die Ausnahme dennoch von der übergeordneten Aufgabe beachtet werden.
Ausnahmen, die auf eine kooperative Kündigung hinweisen
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 Aufgabeninstanz versucht, die Ausnahme zu verbreiten, vergleicht sie das Token in der Ausnahme mit dem Token, das beim Erstellen der Instanz an sie übergeben wurde. Stimmen beide Token überein, gibt die Aufgabe eine TaskCanceledException weiter, die in die AggregateExceptioneingeschlossen ist. Diese ist zu sehen, wenn die inneren Ausnahmen analysiert werden. Wenn der aufrufende Thread jedoch nicht auf die Aufgabe wartet, wird diese spezifische Ausnahme nicht weitergegeben. Weitere Informationen finden Sie unter "Abbruch der Aufgabe".
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
var task = Task.Factory.StartNew(() =>
{
CancellationToken ct = token;
while (someCondition)
{
// Do some work...
Thread.SpinWait(50_000);
ct.ThrowIfCancellationRequested();
}
},
token);
// No waiting required.
tokenSource.Dispose();
Dim someCondition As Boolean = True
Dim tokenSource = New CancellationTokenSource()
Dim token = tokenSource.Token
Dim task1 = Task.Factory.StartNew(Sub()
Dim ct As CancellationToken = token
While someCondition = True
' Do some work...
Thread.SpinWait(500000)
ct.ThrowIfCancellationRequested()
End While
End Sub,
token)
Verwenden der Handle-Methode zum Filtern innerer Ausnahmen
Mit der AggregateException.Handle Methode können Sie Ausnahmen herausfiltern, die Sie als "behandelt" behandeln können, ohne weitere Logik zu verwenden. Im Benutzerdelegaten, der an die AggregateException.Handle(Func<Exception,Boolean>) -Methode weitergegeben wird, können Sie den Ausnahmetyp, seine Message -Eigenschaft oder beliebige andere Informationen analysieren und ermitteln, ob die Ausnahme keine Auswirkungen zeigt. Alle Ausnahmen, für die der Delegat false
zurückgibt, werden in einer neuen AggregateException-Instanz erneut ausgelöst, sobald die AggregateException.Handle-Methode zurückkehrt.
Das folgende Beispiel entspricht funktional dem ersten Beispiel in diesem Thema, das jede Ausnahme in der AggregateException.InnerExceptions Auflistung untersucht. Stattdessen ruft dieser Ausnahmehandler das AggregateException.Handle Methodenobjekt für jede Ausnahme auf, und es werden nur Ausnahmen zurückgegeben, die keine CustomException
Instanzen sind.
public static partial class Program
{
public static void HandleMethodThree()
{
var task = Task.Run(
() => throw new CustomException("This exception is expected!"));
try
{
task.Wait();
}
catch (AggregateException ae)
{
// Call the Handle method to handle the custom exception,
// otherwise rethrow the exception.
ae.Handle(ex =>
{
if (ex is CustomException)
{
Console.WriteLine(ex.Message);
}
return ex is CustomException;
});
}
}
}
// The example displays the following output:
// This exception is expected!
Imports System.Threading.Tasks
Module Example
Public Sub Main()
Dim task1 = Task.Run(Sub() Throw New CustomException("This exception is expected!"))
Try
task1.Wait()
Catch ae As AggregateException
' Call the Handle method to handle the custom exception,
' otherwise rethrow the exception.
ae.Handle(Function(e)
If TypeOf e Is CustomException Then
Console.WriteLine(e.Message)
End If
Return TypeOf e Is CustomException
End Function)
End Try
End Sub
End Module
Class CustomException : Inherits Exception
Public Sub New(s As String)
MyBase.New(s)
End Sub
End Class
' The example displays the following output:
' This exception is expected!
Im Folgenden finden Sie ein vollständigeres Beispiel, in dem die AggregateException.Handle Methode zum Bereitstellen einer speziellen Behandlung für eine UnauthorizedAccessException Ausnahme beim Aufzählen von Dateien verwendet wird.
public static partial class Program
{
public static void TaskException()
{
// This should throw an UnauthorizedAccessException.
try
{
if (GetAllFiles(@"C:\") is { Length: > 0 } files)
{
foreach (var file in files)
{
Console.WriteLine(file);
}
}
}
catch (AggregateException ae)
{
foreach (var ex in ae.InnerExceptions)
{
Console.WriteLine($"{ex.GetType().Name}: {ex.Message}");
}
}
Console.WriteLine();
// This should throw an ArgumentException.
try
{
foreach (var s in GetAllFiles(""))
{
Console.WriteLine(s);
}
}
catch (AggregateException ae)
{
foreach (var ex in ae.InnerExceptions)
Console.WriteLine($"{ex.GetType().Name}: {ex.Message}");
}
}
static string[] GetAllFiles(string path)
{
var task1 =
Task.Run(() => Directory.GetFiles(
path, "*.txt",
SearchOption.AllDirectories));
try
{
return task1.Result;
}
catch (AggregateException ae)
{
ae.Handle(x =>
{
// Handle an UnauthorizedAccessException
if (x is UnauthorizedAccessException)
{
Console.WriteLine(
"You do not have permission to access all folders in this path.");
Console.WriteLine(
"See your network administrator or try another path.");
}
return x is UnauthorizedAccessException;
});
return Array.Empty<string>();
}
}
}
// The example displays the following output:
// You do not have permission to access all folders in this path.
// See your network administrator or try another path.
//
// ArgumentException: The path is not of a legal form.
Imports System.IO
Imports System.Threading.Tasks
Module Example
Public Sub Main()
' This should throw an UnauthorizedAccessException.
Try
Dim files = GetAllFiles("C:\")
If files IsNot Nothing Then
For Each file In files
Console.WriteLine(file)
Next
End If
Catch ae As AggregateException
For Each ex In ae.InnerExceptions
Console.WriteLine("{0}: {1}", ex.GetType().Name, ex.Message)
Next
End Try
Console.WriteLine()
' This should throw an ArgumentException.
Try
For Each s In GetAllFiles("")
Console.WriteLine(s)
Next
Catch ae As AggregateException
For Each ex In ae.InnerExceptions
Console.WriteLine("{0}: {1}", ex.GetType().Name, ex.Message)
Next
End Try
Console.WriteLine()
End Sub
Function GetAllFiles(ByVal path As String) As String()
Dim task1 = Task.Run(Function()
Return Directory.GetFiles(path, "*.txt",
SearchOption.AllDirectories)
End Function)
Try
Return task1.Result
Catch ae As AggregateException
ae.Handle(Function(x)
' Handle an UnauthorizedAccessException
If TypeOf x Is UnauthorizedAccessException Then
Console.WriteLine("You do not have permission to access all folders in this path.")
Console.WriteLine("See your network administrator or try another path.")
End If
Return TypeOf x Is UnauthorizedAccessException
End Function)
End Try
Return Array.Empty(Of String)()
End Function
End Module
' The example displays the following output:
' You do not have permission to access all folders in this path.
' See your network administrator or try another path.
'
' ArgumentException: The path is not of a legal form.
Beobachten von Ausnahmen mithilfe der Task.Exception-Eigenschaft
Wenn ein Vorgang im TaskStatus.Faulted Zustand abgeschlossen ist, kann seine Exception Eigenschaft untersucht werden, um zu ermitteln, welche spezifische Ausnahme den Fehler verursacht hat. Eine gute Möglichkeit, die Exception Eigenschaft zu beobachten, besteht darin, eine Fortsetzung zu verwenden, die nur ausgeführt wird, wenn die vorhergehende Aufgabe fehlerhaft ist, wie im folgenden Beispiel gezeigt.
public static partial class Program
{
public static void ExceptionPropagationTwo()
{
_ = Task.Run(
() => throw new CustomException("task1 faulted."))
.ContinueWith(_ =>
{
if (_.Exception?.InnerException is { } inner)
{
Console.WriteLine($"{inner.GetType().Name}: {inner.Message}");
}
},
TaskContinuationOptions.OnlyOnFaulted);
Thread.Sleep(500);
}
}
// The example displays output like the following:
// CustomException: task1 faulted.
Imports System.Threading
Imports System.Threading.Tasks
Module Example
Public Sub Main()
Dim task1 = Task.Factory.StartNew(Sub()
Throw New CustomException("task1 faulted.")
End Sub).
ContinueWith(Sub(t)
Console.WriteLine("{0}: {1}",
t.Exception.InnerException.GetType().Name,
t.Exception.InnerException.Message)
End Sub, TaskContinuationOptions.OnlyOnFaulted)
Thread.Sleep(500)
End Sub
End Module
Class CustomException : Inherits Exception
Public Sub New(s As String)
MyBase.New(s)
End Sub
End Class
' The example displays output like the following:
' CustomException: task1 faulted.
In einer sinnvollen Anwendung könnte der Fortsetzungsdelegat detaillierte Informationen über die Ausnahme protokollieren und möglicherweise neue Aufgaben zur Wiederherstellung aus der Ausnahme erstellen. Wenn ein Vorgang fehlerhaft ist, lösen die folgenden Ausdrücke die Ausnahme aus:
await task
task.Wait()
task.Result
task.GetAwaiter().GetResult()
Verwenden Sie eine try-catch
-Anweisung, um ausgelöste Ausnahmen zu verarbeiten und zu beobachten. Alternativ können Sie die Ausnahme beobachten, indem Sie auf die Task.Exception Eigenschaft zugreifen.
Von Bedeutung
Dies AggregateException kann nicht explizit abgefangen werden, wenn Sie die folgenden Ausdrücke verwenden:
await task
task.GetAwaiter().GetResult()
UnobservedTaskException-Ereignis
In einigen Szenarien, z. B. beim Hosten nicht vertrauenswürdiger Plug-Ins, können gutartige Ausnahmen häufig vorkommen, und es kann zu schwierig sein, alle manuell zu beobachten. In diesen Fällen können Sie das TaskScheduler.UnobservedTaskException -Ereignis behandeln. Die System.Threading.Tasks.UnobservedTaskExceptionEventArgs Instanz, die an den Handler übergeben wird, kann verwendet werden, um zu verhindern, dass die nicht überwachte Ausnahme wieder an den Verknüpfungsthread weitergegeben wird.