Перекачивать сообщения Windows во время длительной работы? - PullRequest
22 голосов
/ 26 января 2011

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

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

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

Ответы [ 7 ]

19 голосов
/ 26 января 2011

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

6 голосов
/ 26 января 2011

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

3 голосов
/ 26 января 2011

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

3 голосов
/ 26 января 2011

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

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

1 голос
/ 26 января 2011

Традиционный метод 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 голосов
/ 13 ноября 2017

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

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

...