垃圾收集器正在抓取我引用的 TaskCompletionSource
Garbage Collector is grabbing my referenced TaskCompletionSource
考虑下面的片段。
表单将 BusyForm 添加到队列中,稍后,当表单完成时,它会为 TCS 设置结果,将其标记为完成,而不会将项目从队列中移除。
过了一会儿,发生了一些事情,我们需要等待所有繁忙的表单,所以我们 await 每个 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);
}
不清楚这一切是如何组合在一起的,但看起来你的过程应该是:
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
被处理两次的风险。处理仍在队列中的项目似乎很奇怪。想想在机场办理登机手续 - 你在排队时不办理登机手续 - 你会被拉到下一个可用代理人的队伍中。
考虑下面的片段。
表单将 BusyForm 添加到队列中,稍后,当表单完成时,它会为 TCS 设置结果,将其标记为完成,而不会将项目从队列中移除。
过了一会儿,发生了一些事情,我们需要等待所有繁忙的表单,所以我们 await 每个 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);
}
不清楚这一切是如何组合在一起的,但看起来你的过程应该是:
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
被处理两次的风险。处理仍在队列中的项目似乎很奇怪。想想在机场办理登机手续 - 你在排队时不办理登机手续 - 你会被拉到下一个可用代理人的队伍中。