【问题标题】:Pumping Windows Messages During Long Operation?在长时间运行期间泵送 Windows 消息?
【发布时间】:2011-06-15 22:59:52
【问题描述】:

我正在运行的大型操作中收到以下消息:

CLR 无法转换 从 COM 上下文 0x1fe458 到 COM 上下文 0x1fe5c8 持续 60 秒。这 拥有目的地的线程 上下文/公寓最有可能 要么进行非抽水等待,要么 处理很长时间的运行 无抽水操作 Windows 消息。这种情况一般有 负面的性能影响,并可能 甚至导致应用程序变成 无响应或内存使用 随着时间的推移不断积累。到 避免这个问题,全单 线程单元 (STA) 线程 应该使用抽水等待原语 (例如 CoWaitForMultipleHandles)和 在很长一段时间内定期发送消息 运行操作。

如何发送 Windows 消息,以便在长时间操作时不再出现此错误?

【问题讨论】:

  • 有完整源代码的最终解决方案吗?

标签: c# message-pump


【解决方案1】:

目前还不清楚上下文到底是什么——您是在 WinForms 或 WPF 应用程序的 UI 线程上执行一些长时间运行的任务吗?如果是这样,请不要这样做 - 使用BackgroundWorker,或者直接在线程池或新线程上运行任务(如果需要更新 UI,可能使用Control.Invoke/BeginInvokeDispatcher)。如果您的大操作使用正在抱怨的 COM 组件,那就更难了...

【讨论】:

  • 是的,这是在 WinForm 中(抱歉没有在 OP 中指定)。我将尝试在后台工作人员中实现此代码,谢谢!
  • 完成了这个,工作就像一个魅力,再次感谢!
  • @Jon Skeet 您能否详细说明 COM 组件部分?我们有多个线程访问 COM 对象,这会导致 OP 问题。
  • @odyodyodys:听起来我们需要有关您正在使用的 COM 组件的更多信息 - 特别是它使用的线程模型。
  • 我有一个线程处理大量数据,而 UI 等待进度消息。听起来我做得对,但调试器会抛出此消息。等待消息时我应该在 UI 线程中做什么?
【解决方案2】:

据我所知,只有附加的调试器才会发生这种情况。您永远不会在生产中遇到此异常。

【讨论】:

  • 确实没有,因为消息是由 VS 调试器的管理单元生成的。尽管如此,这一事实并没有消除消息警告的潜在问题。
  • 谢谢,我也注意到我的调试器显示了这个警告,即使我的 UI 在那一刻完全响应(我什至有一个我使用 Task.Run 运行的后台任务的进度条,并且进度条是活动的并且是动画的,但是 Visual Studio 仍然显示了这个异常。也许在我的情况下,这与我在 Windows 窗体上使用 WebBrowser 元素的事实有关......
【解决方案3】:

如果在调试器中发生这种情况,可能是由于 ContextSwitchDeadlock MDA,您可以将其关闭(使用 Visual Studio 中的“异常”窗口)。然而,这表明一个更大的问题——你不应该在你的 UI 线程上执行长时间运行的操作。

【讨论】:

    【解决方案4】:

    在这些情况下,我倾向于使用Application.DoEvents。我不知道这是否适用于您的情况。它需要对 System.Windows.Forms 的引用,但也可以在控制台应用程序中使用。

    或者,您可以尝试多线程您的应用程序。

    【讨论】:

    • Application.DoEvents 在这里几乎总是 错误 解决方案,IMO。可能存在一些需要它的边缘情况,但如果它只是“我正在执行一个真正不应该在 UI 线程中运行的长时间运行的操作”,那么将其移出 UI 线程是正确的解决方案。
    • 我完全同意。我最近没有看到错误消息,但我隐约记得我不仅在 UI 线程上看到了它。我认为我已经在长时间运行的 COM 请求中看到了它,但我可能是错的。
    【解决方案5】:

    传统的win32方法是:

    void PumpMessages()
    {
        MSG msg;
        for( ;; ) {
            if( !PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) ) {
                return;
            }
            if( msg.message == WM_QUIT ) {
                s_stopped = true;
                return;
            }
            TranslateMessage( &msg );
            DispatchMessage( &msg );
        }
    }
    

    但我猜你正在使用 .NET。

    【讨论】:

      【解决方案6】:

      我在从 WinForms 项目切换到 ConsoleApp 项目时遇到了这个问题。 Program.cs 中的 Main() 方法从 WinForms 模板中遗留了一个不必要的 [STAThread] 属性。删除该属性会使错误消失。

      【讨论】:

        【解决方案7】:

        您应该在单独的线程上处理长时间运行的操作,以避免冻结 UI。这样也能解决上面的问题

        【讨论】:

          【解决方案8】:

          我知道这是几年前提出的问题,但希望这对以后的其他人有所帮助。如果您不想担心做后台工作者或发送消息,一个简单的解决方法就是简单地更新 UI 上的内容。例如,我有一个只有我使用的工具,所以我不在乎它是否使用 UI 线程。因此,我只需将 UI 上的 textbox.text 更新为我正在处理的任何内容。这是代码的sn-p。这是一种非常hacky,并且可能不正确的专业方法,但它确实有效。

          for (int i = 0; i < txtbxURL.LineCount; i++)
          {
              mytest.NavigateTo(mytest.strURL);
              mytest.SetupWebDoc(mytest.strURL);
              strOutput = mytest.PullOutPutText(mytest.strURL);
              strOutput = mytest.Tests(strOutput);
              mytest.CheckAlt(mytest.strURL);
              mytest.WriteError(txtbxWriteFile.Text);
              txtblCurrentURL.Text = mytest.strURL;
              //This ^^^ is what is being updated, which keeps the thread from throwing the exception noted above.
          }
          

          【讨论】:

            猜你喜欢
            • 2010-12-31
            • 2015-01-25
            • 2021-12-02
            • 2013-01-14
            • 2014-07-15
            • 2012-01-09
            • 2018-03-29
            • 2011-12-11
            • 2016-03-29
            相关资源
            最近更新 更多