Last active
October 15, 2023 04:39
-
-
Save in-async/25d7f2195c0c07ddf445fcff3269f0e6 to your computer and use it in GitHub Desktop.
どっちも同じように OperationCanceledException を投げてるだけなのに、 Task.Status が異なるのなーんでだ
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CancellationToken ct = new CancellationTokenSource(0).Token; | |
Task task1 = Task.Run(() => throw new OperationCanceledException(ct)); | |
Task task2 = Task.Run(() => ct.ThrowIfCancellationRequested()); | |
Task.WhenAll(task1, task2).ContinueWith(_ => { | |
task1.Status.Dump(); // Canceled | |
task2.Status.Dump(); // Faulted | |
}); |
教訓
Task.Run(...)
を使う際は、どのオーバーロードを使用しているか意識する事。
Task.Run(...)
には似たようなオーバーロードが多く、呼び間違えやすいので、注意する必要がある。
そもそも
Task.Run(() => throw new OperationCanceledException(ct));
が Task.Run(Func<Task>)
にオーバーロード解決されてるのが直感的におかしいんだけどな。仕様らしい。
ref.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
task1 の
Task.Run(...)
でスローされたOperationCanceledException
は、 一緒に渡された CancellationToken (default) と異なるので、TaskStatus.Faulted
となる。これは期待通りで、ここまでは task2 も同じ。task1 は
Task.Run(Func<Task>)
なので、 デリゲート実行結果をそのまま返すとTask<Task>
になってしまうが、戻り値の型をTask
にする為にUnwrapPromise
している。https://github.com/dotnet/runtime/blob/9b7c52fa7c4ea7056ffeb7461554f233c9886dfd/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs#L5500-L5502
UnwrapPromise
は、対象の Task が.Faulted
でも例外がOperationCanceledException
でlookForOce
パラメータが true なら.Canceled
と判断しているので、 task1 はTaskStatus.Canceled
になっている。https://github.com/dotnet/runtime/blob/9b7c52fa7c4ea7056ffeb7461554f233c9886dfd/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs#L7120-L7125