【问题标题】:Main thread waiting on background threads that update the interface主线程等待更新界面的后台线程
【发布时间】:2009-08-14 22:39:07
【问题描述】:

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

在做它的工作时,它还会更新主窗口上的进度条。它通过调用 Invoke 来让主线程更新接口来做到这一点。

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

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

但这不起作用!!

后台线程卡在 Invoke 调用上。主线程继续循环调用它的 DoEvents,我认为这就是它需要做的所有事情来获取和处理它的调用。但它不是这样做的......

为什么不!?!

【问题讨论】:

  • 嗨,你把这段代码放在主窗体关闭事件的什么地方?最好的问候,约旦
  • 是的,它在主窗体 form_closing 事件中。

标签: c# .net multithreading


【解决方案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

我希望这会有所帮助。

【讨论】:

  • Join 好像不起作用,它仍然陷入死锁,主线程卡在 Join 上,工作线程卡在 Invoke 上。
【解决方案2】:

我建议将代码放在表单的“关闭”事件中。另外,您可以尝试在Application.DoEvents() 之后添加Thread.Sleep(100)

另外,我会创建一个名为 threadDoneManualResetEvent 或类似的在启动时设置(将 true 传递给事件的构造函数),在线程启动之前重置并由线程设置为指示它完成了工作。

然后你可以重写你的循环如下:

while (!threadDone.WaitOne(100, true))
{
    Application.DoEvents();
    Thread.Sleep(100);
}

这可能会有所帮助 - 但我现在还没有真正尝试过。我通常做的是使用重置事件来检查应用程序或表单是否可以关闭。如果线程没有完成,我会向用户显示一条消息。

【讨论】:

    【解决方案3】:

    主线程不应等待任何其他线程,而应由其他线程发出其工作已完成的信号。

    在您的情况下,我将只使用另一个线程中的 Control.InvokeControl.BeginInvoke 方法来更新 UI。

    【讨论】:

    • 主线程不应该被等待而阻塞,它应该什么都不做。同时 OTHER 线程完成它的工作并通知主线程。
    【解决方案4】:

    好的,我已经从另一个角度解决了这个问题。不再等待线程完成...

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

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

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

    看起来效果不错!

    (感谢大家的尝试。:-))

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-31
      • 2017-05-15
      • 1970-01-01
      相关资源
      最近更新 更多