与从非GUI线程显示MessageBox相关的问题

时间:2010-04-08 08:26:31

标签: .net multithreading invoke messagebox begininvoke

我正在研究一个数据绑定很大的Win.Forms应用程序,我发现了一些奇怪的行为。该应用程序具有单独的I / O线程,通过异步Web请求接收更新 然后,它将其发送到主/ GUI线程,以便处理和更新应用程序范围的数据存储(进而可以将数据绑定到各种GUI元素等)。 Web请求另一端的服务器需要定期请求或会话超时。

我已经完成了几个处理线程问题的尝试解决方案,我发现了以下行为:

  1. 如果我使用Control.Invoke将更新从I / O线程发送到主线程,并且此更新导致显示MessageBox,主表单的消息泵将停止,直到用户单击ok-按钮。这也会阻止I / O线程继续最终导致服务器超时。

  2. 如果我使用Control.BeginInvoke将更新从I / O线程发送到主线程主表单的消息泵停止,但是如果处理更新导致显示消息框,其余更新的处理将暂停,直到用户单击确定。由于I / O线程继续运行并且消息泵继续处理消息,因此可以在具有消息框的那个之前调用几个BeginInvoke用于更新。这会导致无序更新,这是不可接受的。

  3. I / O线程向阻塞队列添加更新(非常类似于Creating a blocking Queue<T> in .NET?)。 GUI线程使用Forms.Timer定期应用阻塞队列中的所有更新。该解决方案解决了阻塞I / O线程和更新顺序性的问题,即下一次更新将永远不会开始,直到上一次完成。但是,性能成本较低,并且在显示更新方面存在延迟,从长远来看这是不可接受的。我希望主线程中的更新处理是事件驱动而不是轮询。

  4. 所以我的问题。我应该怎么做:

    1. 避免阻止I / O线程
    2. 保证更新按顺序完成
    3. 保持主消息泵运行,同时显示更新后的消息框。
    4. 更新:请参阅下面的解决方案

4 个答案:

答案 0 :(得分:5)

MessageBox本身泵出一个消息循环。那当然不是Windows Forms消息循环。一切都正常运行,但减去Control.BeginInvoke()发布的委托调用请求的调度。只有Windows窗体消息循环可以做到这一点。

当在UI线程上进行MessageBox.Show()调用时,会发生这种情况。但是,当它在工作线程上生成时,消息队列是每线程属性。如果你可以将Show调用委托给一个worker,你可能会解决你的问题。

解决您的问题:

  1. 你真的想要相反:工作线程应该阻止。不阻塞会导致重大问题,BeginInvoke调度队列将无限制地填满。一个可能的技巧是计算BeginInvoke调用的数量,在委托目标中倒计时。使用Interlocked类。

  2. 保证BeginInvoke目标的执行顺序。真正的问题可能与工作线程不同步有关。

  3. 在帖子上显示消息框。

答案 1 :(得分:1)

所以你有一个复杂的数据采集和处理链,你想继续运行,然后你在那里插入一个MessageBox。线程+调用中的任何内容都不会改变MessageBox是模态的事实,并且您必须等待它关闭,使整个链依赖于用户点击某些内容。

所以,至少在主路径中摆脱MessageBox。如果处理的一部分确实需要用户干预,则该段必须位于单独的线程上。

答案 2 :(得分:1)

不要使用Forms.Timer从队列中应用更新,而是使用另一个线程来执行此操作。该线程持续监视队列,并且(可能)告诉GUI何时使用新数据刷新自身(通过BeginInvoke)可以从此队列读取器线程显示MessageBox - 不必是GUI线程。


编辑:队列使用者可以调用Control.Invoke来显示messageBox以解决z-order问题

答案 3 :(得分:0)

以下是我最终解决的问题:

  • I / O线程将所有更新放在线程安全/锁定队列中。
  • 单独的工作线程无休止地旋转Dequeing更新,然后BeginInvoke将它们添加到GUI线程中。
  • 现在使用BeginInvoke完成在GUI线程中显示MessageBox以响应更新。

此解决方案与之前的解决方案相比具有以下优势(在上面的3.中使用了用于GUI更新的轮询):

  1. 事件驱动的GUI更新而不是轮询。这样可以提供(理论上)更好的性能和更少的延迟。
  2. 消息框未锁定GUI更新和I / O.
  3. 更新:使用此解决方案显示消息框时,GUI更新似乎仍处于锁定状态。修复时会更新。

    更新2:通过将Invoke更改为BeginInvoke来更新工作线程的修复。