【发布时间】:2012-02-29 15:55:35
【问题描述】:
如果我确定它不会引发异常,那么不引用任务是否安全? 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;
}
附言。老实说,我认为在任务完成之前 TaskScheduler 持有对它的引用(在我的情况下,延续任务也持有对任务数组的引用)。所以 GC 无法从数组中收集延续任务和所有任务,直到它们全部完成。
【问题讨论】:
标签: .net task-parallel-library task