为什么Parallel.For执行WinForms消息泵,以及如何防止它?

Ada*_*dam 5 .net c# 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发生在内部引擎更新期间。

Han*_*ant 4

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

这会触发 Paint 事件,以及其他一些事件,确切的消息过滤是一个严格保守的秘密。它与 DoEvents() 非常相似,但可能导致重入错误的内容被阻止。就像用户输入一样。

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

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