【发布时间】:2012-03-05 05:29:19
【问题描述】:
假设在 Windows 窗体中,我启动了一个长时间运行的任务,如下所示:
ThreadPool.QueueUserWorkItem(new WaitCallback(UpdateDailyTasksChart));
然后,这个函数运行了一段时间,但我在它完成之前关闭了窗口。
private void UpdateDailyTasksChart (object param)
{
//Call Data Access Layer, go get MySQL Data. But I close the Form.
UICallback(chartData); //The Form is closed when this is executed.
}
现在这就是 UICallback 的作用:
private delegate void UICallbackDel(object chartData);
private void UICallback (object chartData)
{
if (InvokeRequired)
{
this.Invoke(new UICallbackDel(UICallback), chartData);
}
else
{
aButtonOnMyForm.Visible = false; //But the Form has been closed!
}
}
奇怪的是,这段代码并没有崩溃。
我在 Form_Closed 事件中放置了断点,它确实执行了。我还没有检查表单是否仍然存在,例如,用类变量声明它。但我的猜测是确实如此。
所以问题是:GC 只会在我的线程完成时收集表单?或者发生了什么?
【问题讨论】:
-
表单是否已明确处理?
-
它是偶然工作的。你很幸运,当表单被处理时, Visible 属性已经是假的,所以实际上没有做任何事情。它不排除炸弹每月一次线程竞赛的可能性。
-
@Hans Passant:但是如果 Form 已经被释放,仅仅访问 Visible 属性就会崩溃,不是吗?无论如何,.Visible 行只是其中之一。我在那里执行了一些其他功能。当线程完成执行并且这些行都没有崩溃时,会对表单进行一些更改。但是由于我没有明确地处理表单,我猜,正如 Phong 所说,GC 还没有完成它的工作,所以表单仍然存在,等待线程结束。这很烦人。我将不得不放弃 ThreadPool 并使用允许更多控制的 Thread 对象。
-
它不能被垃圾收集,您保留对允许您调用实例方法的表单(某处)的引用。这本身就是一个问题,它是一个泄漏。也不小,Form 类对象很大。处理这个问题的唯一明智的方法是实际阻止表单关闭,直到您知道线程不能再调用。此答案涵盖:stackoverflow.com/questions/1731384/…
-
@Hans Passant:我希望能够关闭表单并完全中止线程。尽管我想知道如何在不将任何对 Form 的引用传递给线程的情况下完成此操作,这将阻止它被 GC-ed。也许在 Closing 事件中中止线程会起作用?
标签: c# winforms multithreading