查找阻止UI线程的模块

时间:2010-11-02 15:54:37

标签: c# .net multithreading user-interface

这是一个两部分问题:

  • 我正在开发一个大项目,其中由不同团队开发的多个插件被加载到一个公共容器shell中。有时我可以看到我的UI更新被阻止,因为有多个并行UI更新,我想知道是否有办法找到哪个组件阻止了ui线程

  • 在.net中如何创建需要专门的UI密集型工作的单独UI线程?

非常感谢您的帮助。感谢。

4 个答案:

答案 0 :(得分:4)

使用调试器。当你注意到阻塞时,Debug + Break All。然后Debug + Windows + Threads并选择主线程。调用堆栈窗口显示它正在做什么。

一个极端情况是这些插件使用了很多对Control.Begin / Invoke或Dispatcher.Begin / Invoke的调用。在这种情况下,您的UI线程未被阻止,它只是被调度委托目标的请求所淹没。并且不再能够正常履行其职责,例如重新绘制窗口并响应鼠标和键盘事件。除了与插件作者合作以帮助他们修补他们的方式之外,你几乎无能为力。

你已经有了一个UI线程,即创建第一个窗口的线程。创建具有自己的窗口的其他线程是可能的,但是导致窗口Z顺序无法解决的问题(一个窗口将在另一个应用程序的窗口下面消失)以及窗口互操作线程苦难的慷慨帮助。

答案 1 :(得分:1)

Visual Studio 2010(在较高的SKU中)包含用于检查此功能的功能。如果在Concurrency Profiler下运行程序,则可以确切地看到哪些线程在发生死锁时等待哪些锁。此外,它将突出僵局(我相信亮红色),以便于追踪。

答案 2 :(得分:1)

您可以采取的一种方法(尽管可能需要进行一些重新设计)是禁止所有插件逻辑在UI线程中运行。需要更新UI的所有操作必须通过定义良好的服务接口进行路由,这些接口可以解释,分发甚至可能限制UI更新。这只适用于您的插件不是以UI为中心的,并且您有一个服务模型,允许您将插件操作的数据与该数据的可视化隔离开来。如果不了解您的申请,我无法提供更具体的建议。

答案 3 :(得分:1)

以下是我提出的问题的两种可能解决方案。我确信还有其他同样有效的解决方案。

选项1:而不是使用推送模型(通过ISynchronizeInvoke方法)切换到拉动(或轮询)模型,其中UI查询插件以获取更新。这具有以下优点。

  • 它打破了Control.Invoke强加的UI与工作人员/插件线程之间的紧密联系。
  • 它将更新UI线程的责任放在它应该属于的UI线程上。
  • UI线程决定更新的发生时间和频率。
  • 不存在UI消息泵被覆盖的风险,就像工作人员/插件线程启动的编组技术一样。
  • 在继续执行下一步之前,worker / plugin线程不必等待确认已执行更新(即,您在UI和工作线程/插件线程上获得更多吞吐量)。

选项2 :让插件接受ISynchronizeInvoke个实例,而不是实际的FormControl。这个特殊的同步对象将使用专用线程和作为插件和UI之间的缓冲区的队列来实现。它将通过正常的InvokeBeginInvoke方法接受更新消息,这意味着您可以保持插件架构和接口大部分完整,然后在某种类型的过滤,合并之后将这些消息转发到UI和节流操作已经发生。当UI和插件线程处理负载变化时,同步对象中存在的更新消息的数量将逐渐减少。随着消息速率的增加,改变其转发策略可能足够聪明。