等待更新接口的后台线程的主线程

时间:2009-08-14 10:01:48

标签: c# .net multithreading

是的,我的应用程序偶尔会启动一个后台线程来做一些事情。

在执行其操作时,它还会更新主窗口上的进度条。它通过调用Invoke来获取主线程来更新接口。

当用户关闭应用程序时,我想等到所有后台线程都完成后再关闭表单。在表单结束活动中,我有类似

的内容
            while ( this._Queue.Count > 0 )
            Application.DoEvents ();

但这不起作用!!

后台线程卡在Invoke调用上。主线程继续循环调用它的DoEvents,我认为这是拾取和处理它的调用所需要的全部内容。但它不是这样做的......

为什么不呢??!

4 个答案:

答案 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.InvokeControl.BeginInvoke方法来更新UI。

答案 3 :(得分:0)

是的,我已经从不同的角度解决了这个问题。没有更多的等待线程完成...

我刚在工作线程中添加了一个变量bool KillOnThreadFinish。

然后在关闭主窗体的表单中,检查线程是否正在运行。如果是我设置KillOnThreadFinish = true,我设置e.cancel = true(以防止表单在那时关闭)并设置MainForm.Enabled = false(以防止用户再次关闭表单)。

然后当线程完成其工作时,它会检查KillOnThreadFinish,如果True调用Application.Exit()并且应用程序退出。

似乎工作得很漂亮!

(感谢你们尝试。:-))