問題
Task.WhenAll
メソッドが返すTask
オブジェクトは、引数であたえられたコレクション内のTask
オブジェクトすべてが完了(あるいは例外、中断)すると、IsCompleted
がtrueになる。
では、IsCanceled
, IsFaulted
プロパティはどうなるか。
複数あるタスクのうち、ひとつだけがキャンセルされたときはどうなるか。
このとき、例外をスローしたタスクが混ざっていた場合はどうか。
検証方法
以下のコードで調査をおこなった。
static void Main(string[] args)
{
Console.WriteLine("Empty");
Action(new Task[0]);
Console.WriteLine("");
Console.WriteLine("Completed task");
Action(new[] { CreateNormalTask() });
Console.WriteLine("");
Console.WriteLine("Canceled task");
Action(new[] { CreateCanceledTask() });
Console.WriteLine("");
Console.WriteLine("Faulted task");
Action(new[] { CreateFaultedTask() });
Console.WriteLine("");
Console.WriteLine("Completed task & Canceled task");
Action(new[] { CreateNormalTask(), CreateCanceledTask() });
Console.WriteLine("");
Console.WriteLine("Complated task & Fauleted task");
Action(new[] { CreateNormalTask(), CreateFaultedTask() });
Console.WriteLine("");
Console.WriteLine("Canceled task & Fauleted task");
Action(new[] { CreateCanceledTask(), CreateFaultedTask() });
Console.WriteLine("");
Console.WriteLine("Completed task & Canceled task & Fauleted task");
Action(new[] { CreateNormalTask(), CreateCanceledTask(), CreateFaultedTask() });
Console.WriteLine("");
Console.ReadKey();
}
static void Action(Task[] tasks)
{
var whenAllTask = Task.WhenAll(tasks);
Console.WriteLine($"WhenAllTask: IsCompleted = {whenAllTask.IsCompleted}, IsCanceled = {whenAllTask.IsCanceled}, IsFaulted = {whenAllTask.IsFaulted}");
foreach (var pair in tasks.Select((task, index) => new {task, index}))
Console.WriteLine($" {pair.index}: IsCompleted = {pair.task.IsCompleted}, IsCanceled = {pair.task.IsCanceled}, IsFaulted = {pair.task.IsFaulted}");
}
static Task CreateNormalTask() => Task.CompletedTask;
static Task CreateCanceledTask()
{
var source = new TaskCompletionSource<int>();
source.TrySetCanceled();
return source.Task;
}
static Task CreateFaultedTask()
{
var source = new TaskCompletionSource<int>();
source.TrySetException(new Exception());
return source.Task;
}
実行結果一覧
正常終了したタスク | キャンセルされたタスク | 例外をスローしたタスク | IsCompleted | IsCanceled | IsFaulted |
---|---|---|---|---|---|
あってもなくても | なし | なし | true | false | false |
あってもなくても | あり | なし | true | true | false |
あってもなくても | あってもなくても | あり | true | false | true |
詳細は以下のとおり。
Empty
WhenAllTask: IsCompleted = True, IsCanceled = False, IsFaulted = False
Completed task
WhenAllTask: IsCompleted = True, IsCanceled = False, IsFaulted = False
0: IsCompleted = True, IsCanceled = False, IsFaulted = False
Canceled task
WhenAllTask: IsCompleted = True, IsCanceled = True, IsFaulted = False
0: IsCompleted = True, IsCanceled = True, IsFaulted = False
Faulted task
WhenAllTask: IsCompleted = True, IsCanceled = False, IsFaulted = True
0: IsCompleted = True, IsCanceled = False, IsFaulted = True
Completed task & Canceled task
WhenAllTask: IsCompleted = True, IsCanceled = True, IsFaulted = False
0: IsCompleted = True, IsCanceled = False, IsFaulted = False
1: IsCompleted = True, IsCanceled = True, IsFaulted = False
Complated task & Fauleted task
WhenAllTask: IsCompleted = True, IsCanceled = False, IsFaulted = True
0: IsCompleted = True, IsCanceled = False, IsFaulted = False
1: IsCompleted = True, IsCanceled = False, IsFaulted = True
Canceled task & Fauleted task
WhenAllTask: IsCompleted = True, IsCanceled = False, IsFaulted = True
0: IsCompleted = True, IsCanceled = True, IsFaulted = False
1: IsCompleted = True, IsCanceled = False, IsFaulted = True
Completed task & Canceled task & Fauleted task
WhenAllTask: IsCompleted = True, IsCanceled = False, IsFaulted = True
0: IsCompleted = True, IsCanceled = False, IsFaulted = False
1: IsCompleted = True, IsCanceled = True, IsFaulted = False
2: IsCompleted = True, IsCanceled = False, IsFaulted = True
結論
Task.WhenAll
が返すタスクについて、IsComplated
がtrueのとき、
-
IsCanceled
の値では、キャンセルされたタスクがないことはわからない。例外をスローしたタスクがひとつでもあると、必ずfalseになる。 -
IsFaulted
の値によって、例外をスローしたタスクがあるかどうかがわかる