C# 在长时间运行期间泵送Windows消息?

C# 在长时间运行期间泵送Windows消息?,c#,message-pump,C#,Message Pump,在我正在进行的一项大型行动中,我得到了以下信息: CLR无法转换 从COM上下文0x1fe458到COM 上下文0x1fe5c8持续60秒。这个 拥有目标的线程 上下文/公寓是最有可能的 进行非泵送等待或 处理一个非常长的运行时间 无泵送窗操作 信息。这种情况普遍存在 对绩效产生负面影响,并可能 甚至导致应用程序变得 无响应或内存使用 随着时间的推移不断积累。到 避免这个问题,所有的单 螺纹单元(STA)螺纹 应该使用泵送等待原语 (如CoWaitForMultipleHandles)和 在长时

在我正在进行的一项大型行动中,我得到了以下信息:

CLR无法转换 从COM上下文0x1fe458到COM 上下文0x1fe5c8持续60秒。这个 拥有目标的线程 上下文/公寓是最有可能的 进行非泵送等待或 处理一个非常长的运行时间 无泵送窗操作 信息。这种情况普遍存在 对绩效产生负面影响,并可能 甚至导致应用程序变得 无响应或内存使用 随着时间的推移不断积累。到 避免这个问题,所有的单 螺纹单元(STA)螺纹 应该使用泵送等待原语 (如CoWaitForMultipleHandles)和 在长时间内定期发送消息 运行操作


如何发送windows消息,以便长时间操作不再发生此错误?

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

不清楚上下文到底是什么-您是否正在WinForms或WPF应用程序的UI线程上执行一些长时间运行的任务?如果是这样,请不要这样做-使用
BackgroundWorker
,或者直接在线程池或新线程上运行任务(如果需要更新UI,可以使用
Control.Invoke/BeginInvoke
Dispatcher
)。如果您的大型操作使用的是COM组件,而COM组件正在抱怨,那么这将更加困难……

传统的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。

我倾向于在这些场景中使用。不过,我不知道这在你的情况下是否有效。它需要对System.Windows.Forms的引用,但也适用于控制台应用程序


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

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

据我所知,这种情况只会在附加的调试器上发生。你永远不会在生产中遇到这种例外情况。

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

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.
}
for(int i=0;i
我在从WinForms项目切换到ConsoleApp项目时遇到了这种情况。
Program.cs
中的
Main()
方法从WinForms模板中保留了一个不必要的
[STAThread]
属性。删除属性使错误消失。

Application.DoEvents在这里几乎总是错误的解决方案,我认为。可能有一些需要它的边缘情况,但如果只是“我正在执行一个长时间运行的操作,它实际上不应该在UI线程中”,那么将其从UI线程中移除是正确的解决方案。我完全同意。我最近没有看到错误消息,但我确实隐约记得,我不仅在UI线程上看到过它。我想我已经在长时间运行的COM请求中看到了它,但我可能错了。是的,这是在WinForm中(很抱歉没有在OP中指定)。我将尝试在后台工作人员中实现此代码,谢谢!完成此操作后,工作非常顺利,再次感谢@Jon Skeet您能详细介绍一下COM组件吗?我们有多个线程访问COM对象,这导致了OPs问题。@ODYODYS:听起来我们需要更多关于您正在使用的COM组件的信息,特别是它使用的线程模型。我有一个线程在处理大量数据,而UI在等待进度消息。听起来我做得不错,但是调试器抛出了这些消息。在等待消息时,我应该在UI线程中做什么?是否有完整源代码的最终解决方案?确实没有,因为消息是由VS调试器的管理单元生成的。尽管如此,这一事实并没有消除消息警告的潜在问题。谢谢,我也注意到我的调试器显示了这一警告,即使我的UI当时完全响应(我甚至有一个用于后台任务的进度条,我使用
任务运行它。运行
,进度条处于活动状态并处于动画状态,但Visual Studio仍然显示此异常。在我的情况下,可能与我在Windows窗体上使用WebBrowser元素有关。。。