Skip to content

Instantly share code, notes, and snippets.

@in-async
Last active October 15, 2023 04:39
Show Gist options
  • Save in-async/25d7f2195c0c07ddf445fcff3269f0e6 to your computer and use it in GitHub Desktop.
Save in-async/25d7f2195c0c07ddf445fcff3269f0e6 to your computer and use it in GitHub Desktop.
どっちも同じように OperationCanceledException を投げてるだけなのに、 Task.Status が異なるのなーんでだ
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
});
@in-async
Copy link
Author

気づくのに3日掛かったわ…

@in-async
Copy link
Author

Ans.

Task.Run(...) のオーバーロードが異なるから。

実は task1 は Func<Task> を、 task2 は Action を引数に取ってる。

@in-async
Copy link
Author

in-async commented Oct 15, 2023

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 でも例外が OperationCanceledExceptionlookForOce パラメータが 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

@in-async
Copy link
Author

教訓

Task.Run(...) を使う際は、どのオーバーロードを使用しているか意識する事。

Task.Run(...) には似たようなオーバーロードが多く、呼び間違えやすいので、注意する必要がある。

@in-async
Copy link
Author

そもそも

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