这是一个两部分问题:
我正在开发一个大项目,其中由不同团队开发的多个插件被加载到一个公共容器shell中。有时我可以看到我的UI更新被阻止,因为有多个并行UI更新,我想知道是否有办法找到哪个组件阻止了ui线程
在.net中如何创建需要专门的UI密集型工作的单独UI线程?
非常感谢您的帮助。感谢。
答案 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与工作人员/插件线程之间的紧密联系。 选项2 :让插件接受ISynchronizeInvoke
个实例,而不是实际的Form
或Control
。这个特殊的同步对象将使用专用线程和作为插件和UI之间的缓冲区的队列来实现。它将通过正常的Invoke
或BeginInvoke
方法接受更新消息,这意味着您可以保持插件架构和接口大部分完整,然后在某种类型的过滤,合并之后将这些消息转发到UI和节流操作已经发生。当UI和插件线程处理负载变化时,同步对象中存在的更新消息的数量将逐渐减少。随着消息速率的增加,改变其转发策略可能足够聪明。