Обработка пользовательского интерфейса в многопоточном приложении (или принудительное использование основного потока только для пользовательского интерфейса) - PullRequest
1 голос
/ 13 марта 2010

В моем приложении у меня есть окно 'logging', в котором отображаются все журналы, предупреждения, ошибки приложения. В прошлом году мое приложение было все еще однопоточным, так что это работало [довольно] хорошо.

Теперь я представляю многопоточность. Я быстро заметил, что не стоит обновлять окно регистрации из разных потоков. Читая некоторые статьи о сохранении пользовательского интерфейса в главном потоке, я создал буфер обмена, в который другие потоки добавляют свои сообщения регистрации, и из которого основной поток берет сообщения и показывает их в окне регистрации (это делается в цикл сообщений).

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

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

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

Проблема в том, что в этой ситуации, если другие потоки выполняют ведение журнала, цикл сообщений UI отсутствует, и поэтому буфер связи заполняется, но не очищается.

Я вижу два решения в решении этой проблемы:

  • требует, чтобы основной поток выполнял регулярный опрос буфера связи
  • только выполнение логики пользовательского интерфейса в главном потоке (никакой другой логики)

Я думаю, что второе решение кажется лучшим, но это может быть не так просто внедрить в большое приложение (в моем случае оно выполняет математическое моделирование).

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

Спасибо, Patrick

1 Ответ

1 голос
/ 14 марта 2010

Давайте сначала сделаем заказ.

  • Вы не можете удерживать UI обработку в любое время U заметил бы, или он будет разочарован
  • вы все еще можете выполнять длинные операции в потоке пользовательского интерфейса. это делается с помощью цикла PeakMessage . Если вы разрабатываете один или несколько правильных циклов пиковых сообщений, вам не требуется многопоточность, если только не требуется оптимизация производительности.
  • вы можете рассмотреть цикл MsgWaitForSingleObject () вместо GetMessage, если хотите эффективно взаимодействовать с потоками (всегда лучше, чем опрос)

Поэтому, если вы не перепроектируете свой цикл сообщений

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

О проблеме с памятью:

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

Код интерфейса:

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

Для большинства приложений это просто уловка, потому что пользователи не очень быстро читают. В большинстве случаев лучше разработать другой подход к отображению журналов, возможно, пользовательский интерфейс с отслеживанием состояния, чтобы позволить пользователю выбирать то, что ему интересно в данный момент. Например, Spy ++, некоторые инструменты sysinternals, такие как regmon, filemon, невероятно быстро показывают свои собственные логи. Вы можете взглянуть на их исходный код.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...