複数のTaskの終了待ち中にTaskの中で例外が起きたら、いつどこでアプリが落ちるのか

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