例外をスローしないことがわかっている場合は、タスクを参照解除しても安全ですか? GCは収集する前にタスクが完了するまで待ちますか?タスクを未参照のままにしておくことは安全です
ここでは、タスクの配列を、すべてのタスクが完了したときに完了する(キャンセルまたは失敗した)タスクに変換するメソッドの例を示します。私のアプリケーションは、監視されていない例外で失敗します(タスクを使用する場所でTask.Idを記録することによって、このメソッドに提供されたタスクまたは少なくとも同じIDを持つタスクが検出されました)。私はガベージコレクタがTask.Factory.ContinueWhenAllから返されたタスクを収集することを除いて、どうしてこのようなことが起こるのか分かりません。それは、完了したときに待機しないので、配列からすべての自分のタスクを参照されずに残してしまいます。それはタスクの観察されない例外を導くでしょう。狂ったように聞こえるけど、ヘッペンには別の説明はありません。それは可能ですか?
public static Task ToWhenAllTask(this Task[] tasks, bool cancelIfAnyCanceled = true)
{
if (tasks != null && tasks.Length == 0)
throw new ArgumentException();
var tcs = new TaskCompletionSource<object>();
Task.Factory.ContinueWhenAll(tasks, ts => {
try
{
List<Exception> errors = null;
bool canceled = false;
foreach (Task task in ts)
{
AggregateException ex = task.Exception;
if (ex != null)
{
if (errors == null)
errors = new List<Exception>();
errors.Add(ex.Flatten());
}
if (task.IsCanceled)
canceled = true;
}
if (errors != null)
tcs.TrySetException(errors);
else if (cancelIfAnyCanceled && canceled)
tcs.TrySetCanceled();
else
tcs.TrySetResult(null);
}
catch(Exception ex)
{
// there is nothing to fail in this method but just in case
tcs.TrySetException(ex);
}
}, TaskContinuationOptions.ExecuteSynchronously);
return tcs.Task;
}
PS。正直言って、私はタスクが完了するまで、TaskSchedullerはそれへの参照を保持していると思っていました(私の場合、継続タスクはタスク配列への参照も保持しています)。したがって、GCは、すべてのタスクが完了するまで、継続タスクとすべてのタスクをアレイから収集することはできません。