Перекачка сообщений Windows во время длительной работы?
Я получаю следующее сообщение о большой операции, которую я запускаю:
Среда CLR не может перейти из контекста COM 0x1fe458 в COM контекст 0x1fe5c8 в течение 60 секунд. поток, которому принадлежит место назначения контекст/квартира, скорее всего, либо без ожидания перекачки, либо обработка очень длительная работа без перекачки Windows Сообщения. Эта ситуация обычно имеет отрицательное влияние на производительность и может даже привести к тому, что приложение станет невосприимчивость или использование памяти постоянно накапливаясь с течением времени. к избегайте этой проблемы, все одиночные резьба по резьбе (STA) следует использовать подкачки ожидания перекачки (например, CoWaitForMultipleHandles) и регулярно перекачать сообщения в течение длительного времени выполняемые операции.
Как отправлять сообщения Windows, чтобы эта ошибка больше не выполнялась при длительных операциях?
Ответы
Ответ 1
Непонятно, в чем заключается контекст: выполняете ли вы какую-то долгосрочную задачу в потоке пользовательского интерфейса приложения WinForms или WPF? Если это так, не делайте этого - используйте BackgroundWorker
или запустите задачу в пуле потоков или в новом потоке напрямую (возможно, используя Control.Invoke/BeginInvoke
или Dispatcher
, если вам нужно обновить интерфейс). Если ваша большая операция использует COM-компонент, который жалуется, это будет сложнее...
Ответ 2
Как я знаю, это происходит только с прикрепленным отладчиком. Вы никогда не получите это исключение в производстве.
Ответ 3
Я склонен использовать Application.DoEvents в этих сценариях. Я не знаю, будет ли это работать в вашей ситуации. Он требует ссылки на System.Windows.Forms, но также будет работать в консольных приложениях.
В качестве альтернативы вы можете попробовать многопоточность ваших приложений.
Ответ 4
Если это происходит внутри отладчика, это может быть связано с ContextSwitchDeadlock MDA, которое вы можете отключить (используйте окно "Исключения" в Visual Studio). Однако это указывает на большую проблему - вы не должны выполнять длительные операции с вашим потоком пользовательского интерфейса.
Ответ 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
Вы должны обработать свою длительную операцию в отдельном потоке, чтобы избежать замораживания пользовательского интерфейса. Это также решит проблему выше
Ответ 7
Я знаю, что это задавали несколько лет назад, но надеясь, что это поможет другим в будущем. Если вы не хотите беспокоиться о том, чтобы делать фонового работника или перекачивать сообщения, простое обходное решение просто обновляет что-то в пользовательском интерфейсе. Например, у меня есть инструмент, который только я использую, поэтому мне все равно, использует ли он поток пользовательского интерфейса. Поэтому я просто обновляю 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.
}