4

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

我已经尝试了几种处理线程问题等的解决方案,并且观察到以下行为:

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

  2. 如果我使用 Control.BeginInvoke 将更新从 I/O 线程发送到主线程,则主窗体的消息泵不会停止,但如果更新处理导致显示消息框,则处理其余部分该更新将暂停,直到用户单击“确定”。由于 I/O 线程一直在运行并且消息泵一直在处理消息,因此可能会在消息框完成之前调用多个 BeginInvoke 进行更新。这会导致不可接受的无序更新。

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

所以我的问题。我应该如何做到这一点:

  1. 避免阻塞 I/O 线程
  2. 保证更新按顺序完成
  3. 保持主消息泵运行,同时显示一个消息框作为更新的结果。

更新:请参阅下面的解决方案

4

4 回答 4

5

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

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

解决您的问题:

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

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

  3. 在线程上显示消息框。

于 2010-04-08T11:45:59.253 回答
1

所以你有一个复杂的数据采集和处理链,你想继续运行,但是你在里面插入了一个 MessageBox。Threading+Invoke 中的任何内容都不会改变 MessageBox 是 Modal 并且您必须等待它关闭的事实,从而使整个链依赖于用户单击某些内容。

因此,至少在主路径中摆脱 MessageBox。如果处理的一部分确实需要用户干预,那么该部分必须在单独的线程上。

于 2010-04-08T09:08:55.130 回答
1

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


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

于 2010-04-08T13:01:27.013 回答
0

这是我最终得到的解决方案:

  • I/O 线程将所有更新放在线程安全/锁定队列中。
  • 单独的工作线程无休止地旋转出队更新,然后 BeginInvoke 将它们放入 GUI 线程。
  • 现在使用 BeginInvoke 在 GUI 线程中显示消息框以响应更新。

与以前的解决方案相比,此解决方案具有以下优点(在上面的 3. 中描述,使用轮询进行 GUI 更新):

  1. 事件驱动的 GUI 更新而不是轮询。这提供了(理论上)更好的性能和更少的延迟。
  2. GUI 更新和 I/O 都不会被消息框锁定。

更新:使用此解决方案显示消息框时,似乎 GUI 更新仍被锁定。修复后会更新。

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

于 2010-04-12T11:03:11.623 回答