c# - 具有多个 STA 线程的 Wpf 应用程序仍然阻塞用户界面

标签 c# wpf ironpython dispatcher sta

不久之前,我们使用 IronPython 向 Wpf 应用程序添加了 Python 脚本。起初它只是“奴隶”,例如通过单击按钮调用脚本然后运行完成将控制权返回给 Wpf。后来我们添加了“主”脚本:脚本在它自己的线程中运行,并控制应用程序的其余部分。这非常具有挑战性,但过了一段时间,在现有 SO 内容的帮助下,我们似乎成功了。虽然从来没有真正使用过它,但直到现在,不幸的是它不能正常工作。核心原因是虽然有两个单独的 STA 线程(一个主要的 Wpf 线程和一个用于脚本的线程),因此有两个不同的 Dispatcher 实例,但主线程似乎被阻塞了,因为脚本线程在循环中等待主线程完成(响应在脚本线程上处理的按钮单击和主线程上的启动事件)。使用两个线程和单独的 ui 窗口的全部意义当然是不会发生的。这是怎么回事?

更新 它可以用最少的 code 重现,所以我链接到它而不是在这里发布伪代码。在创建代码时,我发现当脚本线程创建的窗口未嵌入(设置 MainWindow.hostedWin = false)时,不会发生死锁并且一切都按预期运行。

回应评论 因此,有 3 个问题在起作用。我们称它们为 Python、Ui 和 Process。 Python 启动 Process 并等待它完成。进程在 Ui 上调用 Invoke。那个时候不应该做任何事情:毕竟,阻塞的是 Python,而不是 Ui,并且这个构造的全部要点是 Ui 不应该与 Python 交互。好吧,除了它以某种方式起作用。这是罪魁祸首。在死锁中,Ui 位于 PresentationFramework.dll!System.Windows.Interop.HwndHost.OnWindowPositionChanged(System.Windows.Rect rcBoundingBox) + 0x82 字节,Process 位于 WindowsBase.dll!System .Windows.Threading.DispatcherOperation.DispatcherOperationEvent.WaitOne() + 0x2f 字节,Python 就在 Thread.Sleep

这是怎么回事,如何解决?

最佳答案

我会保持简短,这个答案会让您高兴的可能性很小。这是一个三向死锁。最严重的是主线程和PythonThread的交互。此死锁发生在 Windows 内核中,NtUserSetWindowPos() 调用无法进行。它被阻塞,等待 PythonThread 上的 WM_LBUTTONUP 回调通知完成运行。

此死锁是由您的 WpfHwndEmbedHost 黑客攻击引起的。将另一个线程或进程拥有的顶级窗口转变为子窗口是一项旨在支持 Windows 3.x 程序的 appcompat 功能。一个尚不支持线程的 Windows 版本,并且让一个任务嵌入另一个任务的窗口不是问题。委婉地说,WPF 窗口并不完全像这样的窗口。否则,它就是一个众所周知的麻烦制造者,其中一个原因是将 Acrobat Reader 嵌入浏览器窗口效果非常差。 打开 WS_CHILD 样式标志应该会让人松一口气,但 WPF 对此并不满意。只需将 hostedWin 设置为 false 即可解决问题。

另一个死锁是我警告过你的那个,主线程和 ProcessThread 之间的交互。 Dispatcher.Invoke() 很危险,它会死锁,因为主线程卡在内核中。使用 Dispatcher.BeginInvoke() 解决了这个问题。部分地,您仍然让主线程紧张 5 秒。

最严重的问题是内核锁,它会影响许多其他方面。您将不得不将其保留在一个单独的窗口中以避免它。这不是好消息,我敢肯定。

关于c# - 具有多个 STA 线程的 Wpf 应用程序仍然阻塞用户界面,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26201495/

相关文章:

c# - 我应该如何构建我的 View 模型 - ASP.NET MVC

c# - 如何将 WPF 控件文本绑定(bind)到 bool 值,并在 xaml 中决定文本

.net - .Net 上用于 Comet 应用程序的非阻塞网络服务器

c# - 从字符串创建 IronPython(动态)对象

c# - C# 字典序排序

c# - Azure 应用服务中的 IWebHostEnvironment ContentRootPath 与本地不同

c# - 从非托管 C 库访问 C# 方法是否安全?

wpf - ResourceDictionary 中的别名或引用

c# - 调用线程无法访问此对象,因为另一个线程拥有它。如何编辑图像?

c# - 在 IronPython 中导入数学失败