2011-01-26 1 views
18

Я получаю следующее сообщение на большой операции, я бегу:Перекачка сообщений Windows во время длительной эксплуатации?

Среда CLR не смог перейти из COM контекста 0x1fe458 к COM контекста 0x1fe5c8 в течение 60 секунд. Поток , которому принадлежит место назначения Контекст/квартира, скорее всего, либо без ожидания откачки, либо обработка очень долго работает операция без перекачки Windows сообщений. Эта ситуация обычно имеет отрицательное воздействие на производительность и может даже привести к тому, что приложение становится невосприимчивым или используемым в памяти , постоянно накапливающимся с течением времени. Чтобы избежать этой проблемы, вся одиночные резьбовой квартиры (STA) нити должны использовать насосную ожидания примитивы (например, CoWaitForMultipleHandles) и обычно накачать сообщения во время длительных запущенных операций.

Как отправить сообщения Windows, чтобы эта ошибка больше не возникала при длительных операциях?

+0

любое окончательное решение с полным исходным кодом? – Kiquenet

ответ

17

Непонятно, в чем заключается контекст: выполняете ли вы какую-то долговременную задачу в потоке пользовательского интерфейса приложения WinForms или WPF? Если это так, не делайте этого - используйте BackgroundWorker или запустите задачу в пуле потоков или в новом потоке напрямую (возможно, используя Control.Invoke/BeginInvoke или Dispatcher, если вам нужно обновить интерфейс). Если большая операция использует СОМ компонент, который жаловался, что это будет сложнее ...

+0

Да, это в WinForm (извините за то, что не указали это в OP). Я попробую реализовать этот код в фоновом работнике, спасибо! – sooprise

+0

Закончив реализацию этого, работал как шарм, еще раз спасибо! – sooprise

+1

@ Jon Skeet Не могли бы вы рассказать о части COM-компонента? У нас есть несколько потоков, обращающихся к COM-объекту, и это приводит к проблеме OP. – Odys

0

Вы должны обработать свою длинную операцию в отдельном потоке, чтобы избежать зависания пользовательского интерфейса. Это также решит проблему выше

0

Традиционный метод 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.

+0

-1 для адекватного ответа –

3

В этих сценариях я использую Application.DoEvents. Я не знаю, будет ли это работать в вашей ситуации. Он требует ссылки на System.Windows.Forms, но также будет работать в консольных приложениях.

В качестве альтернативы вы можете попробовать многопоточность своих приложений.

+1

Application.DoEvents это почти всегда * неправильное решение здесь, IMO. Там могут быть какие-то крайние случаи, когда это необходимо, но если это просто «я выполняю долговременную операцию, которая действительно не должна быть в потоке пользовательского интерфейса», то переключение с потока пользовательского интерфейса является правильным решением. –

+2

Я полностью согласен. Я недавно не видел сообщение об ошибке, но я смутно помню, что видел его не только в потоке пользовательского интерфейса. Я _think_ Я видел это на длинных запросах COM, но я мог ошибаться. –

3

Если это происходит внутри отладчика, это может быть связано с ContextSwitchDeadlock MDA, которое вы можете отключить (используйте окно «Исключения» в Visual Studio). Однако это указывает на большую проблему - вам не следует выполнять длительные операции в потоке пользовательского интерфейса.

5

Как я знаю, эта вещь происходит только с прикрепленным отладчиком. Вы никогда не получите это исключение в производстве.

+1

Действительно, это не происходит, поскольку сообщение создается с помощью оснастки VS debugger. Тем не менее, этот факт не устраняет основную проблему, о которой предупреждает сообщение. –

+0

Спасибо, я тоже заметил, что мой отладчик показывает это предупреждение, даже когда мой интерфейс полностью реагирует на этот момент (у меня даже есть индикатор выполнения моей фоновой задачи, который я запускаю с помощью 'Task.Run', а индикатор выполнения жив и будучи анимированным, но все же это исключение проявляется в Visual Studio. Возможно, в моем случае это имеет отношение к тому факту, что я использую элемент WebBrowser в своей форме Windows ... – JustAMartin

0

Я знаю, что это задавали много лет назад, но надеемся, что это поможет другим в будущем. Если вы не хотите беспокоиться о том, чтобы делать фонового работника или перекачивать сообщения, простое обходное решение просто обновляет что-то в пользовательском интерфейсе. Например, у меня есть инструмент, который только я использую, поэтому мне все равно, использует ли он поток пользовательского интерфейса. Поэтому я просто обновляю 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. 
}