質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

Q&A

解決済

2回答

2164閲覧

Task.WhenAnyでの例外がキャッチできない

arw.tyx-out_mz

総合スコア27

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

0グッド

1クリップ

投稿2019/07/26 09:23

前提・実現したいこと

Task.WhenAny()を使用して,2つのタスクの実行を行っています.
しかし,CancellationTokenを使用して実行中のタスクをキャンセルした際にOperationCancelledExceptionがキャッチできなくて困っております.

該当のソースコード

C#

1CancellationTokenSource tokenSource; 2void Start() 3{ 4 tokenSource = new CancellationTokenSource(); 5 var _ = DoProcess(tokenSource.Token); 6} 7 8void Stop() 9{ 10 if (tokenSource != null) tokenSource.Cancel(); 11} 12 13async Task DoProcess(CancellationToken token) 14{ 15 try 16 { 17 // これはうまくいく 18 //await Task.Run(() => A(token), token); 19 20 // これもうまくいく 21 //await Task.Run(() => B(token), token); 22 23 // これだと例外をキャッチしてくれない 24 await StartDualTasks(token); 25 } 26 catch (Exception e) 27 { 28 Console.WriteLine($"例外: {e.Message}"); 29 } 30 finally 31 { 32 tokenSource.Dispose(); 33 tokenSource = null; 34 } 35} 36 37async Task StartDualTasks(CancellationToken token) 38{ 39 List<Task> tasks = new List<Task>() 40 { 41 Task.Run(() => A(token), token), 42 Task.Run(() => B(token), token), 43 }; 44 45 await Task.WhenAny(tasks); 46} 47 48void A(CancellationToken token) 49{ 50 while(/*condition*/) 51 { 52 // 処理 53 token.ThrowIfCancellationRequested(); 54 } 55} 56 57void B(CancellationToken token) 58{ 59 while(/*condition*/) 60 { 61 // 処理 62 token.ThrowIfCancellationRequested(); 63 } 64} 65

試したこと

試しにA, Bそれぞれ単体で実行してみたところ,問題なく例外が発生してくれました.
しかし,2つを同時にスタートするとうまくいきません.
Task.WhenAnyを使用するときは特殊な例外のハンドリングが必要なのでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

こんにちは。

今検証してみましたが、確かに Task.WhenAny はどれか一つの Task が完了ではなく失敗やキャンセルになっても、WhenAny としては「完了」として次に進むようです。
罠っぽい挙動ですが、そういうものなのでしょう。
WhenAny の戻り値が「最初に完了した(判定に用いた) Task」そのものなので、これのステータスを覗くと Canceled になっていることが確認できます。
または、これを await すると、その場でキャンセル例外が投げられることが確認できます。

投稿2019/07/26 10:09

tamoto

総合スコア4103

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

arw.tyx-out_mz

2019/07/26 10:17

そういうものなんですね...... トラップに引っかかりました笑 `または、これを await すると、その場でキャンセル例外が投げられることが確認できます` この文章の"これ"ってWhenAnyの戻り値のことを指していますか?
tamoto

2019/07/26 10:22

そうです。 WhenAny の戻り値 (== 最初にキャンセルされた Task) は状態が Canceled なので、それを await した瞬間に例外を吐きます。 非同期メソッド中で TaskCanceledException を catch しなければ、その非同期メソッド自体も Canceled 状態になります。
arw.tyx-out_mz

2019/07/26 14:16

なるほど!よくわかりました! ありがとうございます
guest

0

stackoverflowにこのような質問がありました。

C#

1Task t = await Task.WhenAny(tasks); 2await t;

とすれば例外が取れるかと思います。

投稿2019/07/26 11:31

YAmaGNZ

総合スコア10222

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

YAmaGNZ

2019/07/26 11:32

あぁ、tamotoさんと同じこと書いてますね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問