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

Han*_*ken 4 .net multithreading messagebox invoke 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线程向阻塞队列添加更新(非常类似于在.NET中创建阻塞队列<T>).GUI线程使用Forms.Timer定期应用阻塞队列中的所有更新.此解决方案解决了阻塞I/O线程和更新顺序的问题,即下一次更新将永远不会开始,直到上一次完成.但是,性能成本较低,并且在显示更新方面存在延迟,从长远来看这是不可接受的.我希望主线程中的更新处理是事件驱动而不是轮询.

所以对我的问题.我应该怎么做到:

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

更新:见下面的解决方案

Han*_*ant 5

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

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

解决你的问题:

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

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

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