2016-05-31 22:42:56

Uruchamianie asynchronicznych metod bez await - ogólnie nie polecam

Podczas implementowania jednego z ficzerów aplikacji w pracy popełniłem metodę, w której uruchomiłem asynchroniczną metodę bez awaita.

Metoda miała i tak być odpalona w trybie "Fire and forget" więc uznałem wpisywanie tych kilkunastu znaków za stratę czasu i puściłem moduł na testy, które to testy moduł przeszedł. Jednak w przeciągu tygodnia użytkownicy zaczęli się skarżyć że aplikacja się przewraca w losowych momentach. Logi wskazywały, że mechanizm globalnej obsługi wyjątków loguje błąd o szczegółach podobnych do następujących:

Message:Wyjątków zadania nie zaobserwowano ani przez oczekiwanie na zadanie, ani przez uzyskanie dostępu do jego właściwości Exception. W wyniku tego niezaobserwowany wyjątek został wywołany ponownie przez wątek finalizatora.
Stack trace: 

Caused by:

Message:Zgłoszono wyjątek typu 'System.Exception'.
Stack trace: 
 

 

Niewiele da się z tego odczytać. Uratował mnie jednak fakt iż typ wyjątku był mi bardzo dobrze znany (i nie był to System.Exception). 
Dodanie awaita sprawiło, że stos zaczął wyglądać po ludzku:

Message:Zgłoszono wyjątek typu 'System.Exception'.
Stack trace:
   w System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   w System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   w Szogun1987.TaskExceptions.MainWindow.<WithAwaitAndCompletionSource_Click>d__3.MoveNext() w D:\Projekty\Szogun1987.TaskExceptions\src\Szogun1987.TaskExceptions\Szogun1987.TaskExceptions\MainWindow.xaml.cs:wiersz 30
--- Koniec śladu stosu z poprzedniej lokalizacji, w której wystąpił wyjątek ---
   w System.Runtime.CompilerServices.AsyncMethodBuilderCore.<>c.<ThrowAsync>b__6_0(Object state)
   w System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   w System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)

 

Przygotowałem też programik obrazujący problem: https://github.com/szogun1987/TaskExceptions
Błąd wykazuje największą powtarzalność po zbudowaniu w wersji Release. Gdyby błąd nie chciał wystąpić należy wcisnąć przycisk GC.Collect.

Tagi

C Sharp

Komentarze: