Подтвердить что ты не робот

Избегание метки "(не реагировать)" в окнах при обработке большого количества данных в одном компе

Мне иногда приходится обрабатывать большой объем данных из одного пакета из сети, который занимает достаточно много времени, когда пользователь пытается взаимодействовать с окнами приложения, добавляет строку "(Не реагирует)" в заголовок окна. Я знаю, что это происходит потому, что обработка выполняется во время вызова обработки сообщения (каким-то образом вверх по стеку) и, следовательно, блокирует насос сообщений. Я также знаю, что идеальный способ справиться с этим заключается в том, чтобы обрабатывать данные асинхронно в отдельном потоке, чтобы насос мог продолжать работать, однако это настольное приложение LARGE, которое однопоточно с верхней и нижней стороны и безопасно откручивает эту обработку не представляется возможным в наши рамки времени.

Таким образом, имея в виду, есть ли шанс, что я могу, по крайней мере, избежать "не отвечающего" прозвища (который большинству пользователей читает как "разбился" ), сообщая окнам, что мое приложение будет занято раньше Я начинаю работу? Я считаю, что есть что-то в этом направлении, когда вы отвечаете на запрос о закрытии, можно продолжать просить окна больше времени, чтобы избежать провозглашения того, что вы не "закрываете своевременно"

Я должен добавить это приложение С++ MFC.

4b9b3361

Ответ 1

Я не думаю, что Windows API может вам помочь.

Альтернативно, как насчет отображения диалогового окна с индикатором выполнения и запуска его в отдельном потоке?

В диалоговом окне может также быть использован текст типа "Эта операция может занять полчаса".

Ответ 2

Хорошо, во-первых, я поддержал пост Фредерика, потому что, как это или нет, второй поток, вероятно, лучший способ пойти.

Однако, если вы действительно не хотите идти по этой дороге, вы можете вручную переключить очередь сообщений внутри внутреннего цикла приложений. Что-то вроде этого;

int Refresh()
{
    MSG       msg;
    if (PeekMessage (&msg, NULL, 0, 0,PM_NOREMOVE))
        if ((msg.message == WM_QUIT) 
          ||(msg.message == WM_CLOSE) 
          ||(msg.message == WM_DESTROY) 
          ||(msg.message == WM_NCDESTROY)
          ||(msg.message == WM_HSCROLL)
          ||(msg.message == WM_VSCROLL)
          ) 
          return(1); 
    if (PeekMessage (&msg, NULL, 0, 0,PM_REMOVE))
    {
        TranslateMessage (&msg);
        DispatchMessage (&msg);
    }
    return(0);
}

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

Ответ 3

Вам не нужно ничего делать с сообщениями из PeekMessage. Просто позвоните PeekMessage, вам даже не нужно ничего удалять из очереди или обрабатывать. До тех пор, пока он вызывается каждые 5 секунд или около того, это заставит окна думать, что процесс все еще реагирует.

Альтернативной идеей является наличие отдельного процесса/потока, который появится в лотке уведомлений, и сообщит пользователю, что процесс занят, ожидая завершения внутренней операции. Вы увидите их в более поздних версиях Visual Studio, SQL Server Management Studio и т.д.

Ответ 4

Если вы откажетесь от потока, скорее всего, вас беспокоит какое-то другое действие пользователя, которое может зависеть от результата продолжительной операции (да, concurrency). Так что, расширившись на то, что сказал Фредрик, если вы начнете откручивать новый поток и устанавливаете индикатор выполнения, вы можете заблокировать фокус на индикатор прогресса, чтобы пользователь не мог взаимодействовать с остальной частью приложения. Этого должно быть достаточно, чтобы реализовать действительно простой второй поток, не беспокоясь о concurrency, потому что вы по существу блокируете остальную часть приложения, отключив пользовательское вмешательство.

Ответ 5

Вам нужно будет чередовать обработку с обработкой сообщений. Если нить не может быть и речи, вы можете захотеть разделить обработку на несколько этапов. Один из способов сделать это - выполнить некоторую обработку при первом получении пакета, а затем отправить сообщение в приложение, в котором говорится: "Продолжайте обработку здесь". Когда приложение получит сообщение "продолжить обработку здесь", оно сделает еще некоторую обработку и отправит другое сообщение "продолжить обработку здесь" или закончит.

Есть несколько соображений:

  • Вам нужно убедиться, что состояние приложения согласовано каждый раз, когда вы отправляете сообщение самому себе и откладываете его до цикла сообщений, поскольку другая обработка сообщений может произойти в среднем. Это можно сделать, например, только изменяя состояние на заключительной фазе обработки.
  • Другой пакет может появиться, пока вы все еще обрабатываете первый пакет. Если изменение порядка обработки будет плохо для приложения, вы можете справиться с этим, например. отправляя сообщение "напоминать мне, чтобы обработать этот пакет позже", когда это произойдет.

Я не знаю, было ли это осуществимо в дизайне вашего приложения, но это был бы один из способов решения проблемы.

Ответ 6

Win32 имеет метод для этого в user32.dll.

DisableProcessWindowGhosting()

Отключает функцию ghosting окна для процесса вызова GUI. Window ghosting - это функция диспетчера Windows, которая позволяет пользователю минимизировать, перемещать или закрывать главное окно приложения, которое не отвечает.

В дополнение к описанному выше документированному поведению, я также проверил здесь (в приложении С#), что этот вызов Win32 также запрещает появление ярлыка Not Responseing в окне.

Я нашел это через ответ С# на похожий вопрос здесь: fooobar.com/questions/421057/....

Ответ 7

Если вы не хотите порождать рабочий поток, но вы можете разбить долговременную задачу на более мелкие части, вы можете выполнить обработку в MFC CWinApp::OnIdle. Эта функция вызывается из цикла сообщений, если нет ожидающих сообщений Windows. Пока работа, которую вы выполняете в каждом вызове OnIdle, достаточно коротка, вы не отвлекаете внимание своего приложения.

Ответ 8

Предполагая, что это обработка данных, которые занимают все время, а не прием (и вы серьезно относитесь к тому, чтобы избежать потока, который является хорошим IMOHO) данных, которые вы могли:

  • В функции, которую вы в настоящее время обрабатываете сообщение, создайте модальный диалог, в котором отображается сообщение "пожалуйста, подождите" (или сделайте его скрытым, маленьким, любым...). Скопируйте (или отправьте указатель и т.д.) Данные, которые вы обрабатываете, в переменную-член этого диалога.
  • В текстовом окне диалога пользовательское сообщение для себя обрабатывает данные.
  • В обработчике сообщений диалога обрабатывайте один "блок" работы. Следите за тем, что следующая "единица" работы. Повторите одно и то же сообщение.
  • Повторите это сообщение "loop" до завершения. Закройте диалоговое окно.

Характер модального диалога заставит вас "реагировать" на приложение, с минимальным прерыванием или изменением того, как приложение работало ранее. Reentrancy может быть проблемой с модальными циклами, особенно если это связано с сообщением WM_PAINT. (кто-либо когда-либо утверждал, что внутри кода живописи хорошие времена, хорошие времена...)

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