Task関連記事
https://tera1707.com/entry/2022/02/06/144447#Task
やりたいこと
以前、「Taskの中で例外が起きた時のキャッチの仕方」で、Taskの中で例外があったときにどうcatchしたらいいかを調べた。
その時は、動き出した直後に例外を起こすようなTaskで実験をしていた。
以下は、①awaitで待つときのパターンより。
// awaitしたTaskの例外 private async void Button_Click(object sender, RoutedEventArgs e) { try { await Task.Run(() => { throw new NotImplementedException(); }); } catch (Exception ex) { Debug.WriteLine("1:" + ex.GetType()); } }
今回、数秒処理をしたあとに例外を起こすようなTaskがあり、そのTaskを含めて複数のTaskの終了をTask.WaitAll()
で待つ処理があった。
その部分で、どう例外を受けてやるか?は、前回記事で勉強したが、「いつ」例外を起こすのか、がわからなかった。それを調べてみる。
やったこと
時間差で、完了&例外を起こすTaskを作成し、どこでどう例外を起こすのか、テストプログラムで試してみた。
〇時間差で例外起こすTaskをWaitAll()で待つ
private async void Button_Click_1(object sender, RoutedEventArgs e) { var l = new List<Task>(); l.Add(Task.Run(() => { Thread.Sleep(5000); })); l.Add(Task.Run(() => { Thread.Sleep(10000); throw new InvalidOperationException("例外1"); })); l.Add(Task.Run(() => { Thread.Sleep(15000); })); //await Task.WhenAll(l); Task.WaitAll(l.ToArray()); Debug.WriteLine("終了."); }
結果
実行して10秒後
例外がスローされました: 'System.InvalidOperationException' (WpfApp1.dll の中)
実行して15秒後
例外がスローされました: 'System.AggregateException' (System.Private.CoreLib.dll の中) 型 'System.AggregateException' の例外が System.Private.CoreLib.dll で発生しましたが、ユーザー コード内ではハンドルされませんでした One or more errors occurred.
デバッグ実行ではなく、exeを直叩き(or Ctrl+F5)の場合は、例外キャッチしてないのでアプリが落ちる。(15秒後)
〇時間差で例外起こすTaskをWhenAll()で待つ
private async void Button_Click_1(object sender, RoutedEventArgs e) { var l = new List<Task>(); l.Add(Task.Run(() => { Thread.Sleep(5000); })); l.Add(Task.Run(() => { Thread.Sleep(10000); throw new InvalidOperationException("例外1"); })); l.Add(Task.Run(() => { Thread.Sleep(15000); })); await Task.WhenAll(l); //Task.WaitAll(l.ToArray()); Debug.WriteLine("終了."); }
結果
実行して10秒後
例外がスローされました: 'System.InvalidOperationException' (WpfApp1.dll の中)
実行して15秒後
例外がスローされました: 'System.InvalidOperationException' (System.Private.CoreLib.dll の中) 型 'System.InvalidOperationException' のハンドルされていない例外が System.Private.CoreLib.dll で発生しました 例外1
exeを直叩きの場合は、WaitAllと同じで15秒後にアプリが落ちる。
〇時間差で例外起こすTaskを待たない
private async void Button_Click_1(object sender, RoutedEventArgs e) { var l = new List<Task>(); l.Add(Task.Run(() => { Thread.Sleep(5000); })); l.Add(Task.Run(() => { Thread.Sleep(10000); throw new InvalidOperationException("例外1"); })); l.Add(Task.Run(() => { Thread.Sleep(15000); })); //await Task.WhenAll(l); //Task.WaitAll(l.ToArray()); Debug.WriteLine("終了."); }
結果
実行直後
終了.
実行して10秒後
例外がスローされました: 'System.InvalidOperationException' (WpfApp1.dll の中)
まとめ
WhenAllではTaskの中で起きた例外のうちの一つがそのまま上がってくる、 WaitAllではTaskの中で起きた例外がAggregateExceptionに包まれて上がってくる、は以前調べた通り。
例外が起きるタイミング(catchしてないとアプリが落ちるタイミング)は、WhenAllやWaitAllで、すべてのTaskが終わった時点で例外が起きる。
参考
自分の以前のTask関連記事
https://tera1707.com/entry/2022/02/06/144447#Task
[C#] Taskの中で例外が起きた時のキャッチの仕方
https://qiita.com/tera1707/items/d5a3bc12ffa5f80069a1