垃圾收集器正在抓取我引用的TaskCompletionSource

时间:2015-04-09 14:18:46

标签: c# garbage-collection objectdisposedexception

考虑下面的摘录。
表单将 BusyForm 添加到队列中,稍后,当表单完成时,它会设置TCS的结果,将其标​​记为完成,而不从队列中删除该项目。
过了一会儿,有些事情发生了,我们需要等待所有繁忙的表单,所以我们等待每个TCS任务 在队列中。但惊讶,惊讶.. GC抓住了它。

为什么呢?它不是由队列引用的吗?

static class Global
{
    public static ConcurrentQueue<BusyForm> BusyForms = new ConcurrentQueue<BusyForm>();

    public class BusyForm
    {
        public string Name;
        public TaskCompletionSource<bool> Done = new TaskCompletionSource<bool>();

        public BusyForm(string name)
        {
            this.Name = name;
        }
    }
}
// somewhere else when form is done
busyForm.Done.SetResult(true);
// after a while, when required
while(!Global.BusyForms.IsEmpty)
{
    Global.BusyForms.TryPeek(out busyForm);
    await busyForm.Done.Task; // can be disposed by GC if finished a long time ago
    Global.BusyForms.TryDequeue(out busyForm);
}

1 个答案:

答案 0 :(得分:1)

目前尚不清楚这一切是如何组合在一起的,但似乎你的过程应该只是:

while(!Global.BusyForms.IsEmpty)
{
    if(Global.BusyForms.TryDequeue(out busyForm))
        await busyForm.Done.Task; // can be disposed by GC if finished a long time ago
    else
    {
         // could not dequeue for some reason - need to break the loop so that we no not get in an infinite loop.  
         break;
         // or perhaps throw an exception?
    }
}

这样就不会有同样Task被处理两次的风险。当一个项目仍然在队列中时处理它似乎很奇怪。考虑在机场办理登机手续 - 在排队时不办理登机手续 - 您将被拉出线路,以便下一个可用的代理人服务。