c# - 为什么 Parallel.For 会执行 WinForms 消息泵,如何防止?

标签 c# .net winforms task-parallel-library parallel.foreach

我正在尝试使用 Parallel.For 来加速一个冗长(几毫秒)的操作*,但是在该方法返回之前,我在我的 WinForms 应用程序中得到了 Paint 事件 - 建议它以某种方式触发消息泵。但是,整体重绘会导致在不一致的状态下访问数据,从而产生不稳定的错误和异常。我需要确保 Parallel.For 在阻塞时不会触发 UI 代码。

到目前为止,我对此的研究尚无定论,并粗略地指出了诸如同步上下文和 TaskScheduler 实现之类的东西,但我还没有弄清楚这一切。

如果有人可以帮助我解决一些问题,我将不胜感激。

  1. 导致 Parallel.For 触发 WinForms 消息泵的事件链是什么?
  2. 有什么办法可以完全避免这种情况的发生?
  3. 或者,是否有任何方法可以判断 UI 事件处理程序是从常规消息泵调用,还是从 Parallel.For 触发的“繁忙”消息泵调用?

编辑: * 一些上下文:上面几毫秒的操作是游戏引擎循环的一部分,其中 16 毫秒可用于完整更新 - 因此属性“冗长”。这个问题的上下文是在它的编辑器中执行一个游戏引擎核心,它是一个 WinForms 应用程序。 Parallel.For 发生在内部引擎更新期间。

最佳答案

这来自 CLR,它实现了永远不允许 STA 线程(又名 UI 线程)阻塞在同步对象上的契约。就像 Parallel.For() 一样。它泵以确保不会发生死锁。

这会触发 Paint 事件,以及其他一些事件,确切的消息过滤是一个保密的 secret 。它与 DoEvents() 非常相似,但可能导致重入错误的东西被阻止了。比如用户输入。

但是很明显你有一个 DoEvents() 风格的错误,重入永远是一个讨厌的错误生成器。我怀疑您只需要设置一个 bool 标志以确保 Paint 事件跳过更新,这是最简单的解决方法。将 Program.cs 中 Main() 方法的 [STAThread] 属性更改为 [MTAThread] 也是一个简单的修复,但如果您还有正常的 UI,则风险很大。喜欢 private bool ReadyToPaint; 方法,推理起来最简单。

然而,您应该确切地调查为什么 Winforms 认为需要 Paint,它不应该,因为您可以控制游戏循环中的 Invalidate() 调用。它可能因用户交互而触发,例如最小/最大/恢复窗口,但这种情况应该很少见。地垫下隐藏着另一个 bug 的可能性非零。

关于c# - 为什么 Parallel.For 会执行 WinForms 消息泵,如何防止?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35535580/

相关文章:

.net - 复制/粘贴 Treeview 节点标签

c# - 如何将用户控件添加到组框

.net - Windows 窗体的 CheckBox CheckedChanged 与 CheckStateChanged

c# - C# 中的计划操作,带有立即 FullStop 选项

c# - 在 C#/Mono 中序列化至 Adob​​e AMF 或从 Adob​​e AMF 序列化?

c# - 从 32 位应用程序使用 64 位库

c# - 选择在运行时保存文件的位置

c# - 根据 bindingcontext 删除 ListView item

c# - 无法让 Dynamic Linq 工作

c# - 如何使用 XAML 中的资源值和绑定(bind)值格式化字符串?