Перекачка Сообщений Windows Во Время Длительной Работы?

Я получаю следующее сообщение о большой операции, которую я выполняю:

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

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

7 ответов


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


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


Я предпочитаю использовать приложение.Функция doevents в этих сценариях. Я не знаю, сработает ли это в вашей ситуации. Это требует Ссылки на систему.Окна.Формы, но также будут работать в консольных приложениях.

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


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


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

но я понимаю, что вы используете .Сеть.


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


Я знаю, что это было задано много лет назад, но надеюсь, что это поможет другим вниз по дороге. Если вы не хотите беспокоиться о выполнении фонового рабочего или перекачки сообщений, простым обходным путем является просто обновление чего-то в пользовательском интерфейсе. Например, у меня есть инструмент, который только я использую, поэтому мне все равно, использует ли он поток пользовательского интерфейса. Поэтому я просто обновляю текстовое поле.текст в пользовательском интерфейсе к тому, над чем я работаю. вот фрагмент кода. Это очень хакерский и, вероятно, неправильный способ сделать это профессионально, но это работает.

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.
}