是的,我的应用程序偶尔会启动一个后台线程来做一些事情。
在执行其操作时,它还会更新主窗口上的进度条。它通过调用Invoke来获取主线程来更新接口。
当用户关闭应用程序时,我想等到所有后台线程都完成后再关闭表单。在表单结束活动中,我有类似
的内容 while ( this._Queue.Count > 0 )
Application.DoEvents ();
但这不起作用!!
后台线程卡在Invoke调用上。主线程继续循环调用它的DoEvents,我认为这是拾取和处理它的调用所需要的全部内容。但它不是这样做的......
为什么不呢??!
答案 0 :(得分:1)
BackgroundWorker提供了一种运行后台线程的便捷方式,同时允许使用.NET事件轻松报告进度。您可以将ProgressBar UI更新连接到ProgressChanged事件处理程序,并通过RunWorkerCompleted向您报告完成情况。如果您只有一个后台线程,这比滚动您自己的线程处理代码要简单得多。这是MSDN文章:
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
如果您坚持使用常规线程,那么我会考虑使用Join来等待线程完成。这样可以处理正常的消息,并在紧密的循环中保存轮询。这里有更多信息:
http://msdn.microsoft.com/en-us/library/95hbf2ta.aspx
此外,还有一些重载采用超时参数(Int32表示毫秒或TimeSpan对象)。如果在此时间过后线程尚未完成,则抛出异常。这有助于捕获在您尝试关闭时卡住的线程。更多信息:
http://msdn.microsoft.com/en-us/library/6b1kkss0.aspx
我希望这会有所帮助。
答案 1 :(得分:0)
我建议将代码放在表单的“Closing”事件中。另外,您可以尝试在Thread.Sleep(100)
之后添加Application.DoEvents()
。
另外,我创建一个名为ManualResetEvent
或类似的threadDone
,它在启动时设置(将true
传递给事件的构造函数),在线程启动之前重置并且是由线程设置表明它已完成工作。
然后你可以按如下方式重写你的循环:
while (!threadDone.WaitOne(100, true))
{
Application.DoEvents();
Thread.Sleep(100);
}
这可能会有所帮助 - 但我现在还没有尝试过。我通常做的是使用重置事件来检查应用程序或表单是否可以关闭。如果线程没有完成,我会向用户显示一条消息。
答案 2 :(得分:0)
主线程不应该等待任何其他线程,而是另一个线程应该发出信号表明其工作已经完成。
在您的情况下,我只会使用其他线程中的Control.Invoke
或Control.BeginInvoke
方法来更新UI。
答案 3 :(得分:0)
是的,我已经从不同的角度解决了这个问题。没有更多的等待线程完成...
我刚在工作线程中添加了一个变量bool KillOnThreadFinish。
然后在关闭主窗体的表单中,检查线程是否正在运行。如果是我设置KillOnThreadFinish = true,我设置e.cancel = true(以防止表单在那时关闭)并设置MainForm.Enabled = false(以防止用户再次关闭表单)。
然后当线程完成其工作时,它会检查KillOnThreadFinish,如果True调用Application.Exit()并且应用程序退出。
似乎工作得很漂亮!
(感谢你们尝试。:-))