Форум программистов, компьютерный форум, киберфорум
krapotkin
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
Блог. Двадцать пять лет Делфи-практики

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

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

Начав с Делфи-2 двадцать пять лет назад, я прошел все версии, испробовал массу технологий, включая работу с БД, с графикой DirectX, связью с серверами и интернетом, разработку на Андроид и IOS, и многое, многое другое.
________________________________________ ________________________________________ ____
P.S. все, о чем здесь написано, всего лишь измышления из головы.
совпадения с реальными людьми и фактами случайны.

ProcessMessages

Запись от krapotkin размещена 30.08.2017 в 06:54
Показов 13446 Комментарии 9
Метки delphi

Как только я вижу в чьем-то коде Application.ProcessMessages, я сразу вспоминаю -
несчастные случаи на стройке

Поясню:
Вся программа на делфи выглядит примерно так
Delphi
1
2
3
Application.Initialize;
Application.CreateForm(Form1,TForm1);
Application.Run;
вот если посмотреть код в Application.Run, мы увидим (весьма примерно)
Delphi
1
2
while not Application.Terminated do
  Application.ProcessMessages;
итого. пока приложению никто не сказал закрыться, оно всего лишь смотрит в свою очередь сообщений и вызывает обработчики этих сообщений.
Сообщений сотни - каждое движение мыши, таймеры, перерисовка окантовки и заголовка окон, вообще все в Windows делается по сообщениям.
И вот при обработке сообщения программа вызывает ваш обработчик события. Например, нажатия кнопки.
А там вы делаете что-то очень важное для вас и хуже всего - длительное по времени.
И тут встает проблема. Перерисовка окна и обработка ввода идут тоже через сообщения, а программа еще не вышла из вашего обработчика и никаких сообщений не обрабатывает, и все говорят - висит!
Да нет, не висит, вы сами ее чем-то заняли, она работает. Чаще всего в к-нить вашем цикле, или качает что-то из интернета.
И для простого решения проблемы "зависания" программист пишет Application.ProcessMessages!
И вуаля - программа перерисовывает окно и даже вызывает еще какой-то обработчик мыши.
И тут начинаются спецэффекты
Напоминаю. Ваш обработчик вызван из какой-то процедуры компонента, которая по цепочке вызвана из обработчика события Application.ProcessMessages. И вы тоже вызываете ProcessMessages. Да еще в цикле!
Получится
ProcessMessages -- Обработчик сообщения -- Процедуры объектов -- Ваш обработчик -- ProcessMessages -- Обработчик сообщения -- Процедуры объектов -- ????
и вот тут запросто может быть заново вызван ваш обработчик опять!!! И дальше все по кругу...
Либо как вариант, компонент может полагаться на последовательные вызовы событий типа
OnCreate -- OnShow -- OnActivate
а тут еще Create не закончился, а уже Show. oO
Программа становится НЕЛИНЕЙНОЙ!
В нормальном состоянии ваши процедуры отрабатывают друг за другом, от начала и до конца. Никаких параллельностей.
Тут же это не так! Следующие процедуры запросто вызываются, когда еще не закончилась текущая. А потом текущая продолжится!

Конечно, не всегда это приводит к печальным последствиям, но делать так НЕ СТОИТ!
А если сделали, не удивляйтесь!

Иногда вместо ProcessMessages достаточно просто перерисовать компонент Component1.Update;
Иногда длительное действие нужно вынести в отдельный поток.
С потоками решение сложной задачи можно разбить на два этапа - старт задачи и, отдельно - получение результата, когда задача завершилась. Тогда программа может заниматься своими делами, когда расчет (или загрузка файла или...) будет закончен, вызовется обработчик, где вы решите, что делать с результатом.

Решения есть. Не ленитесь.
И перестаньте вставлять Application.ProcessMessages.

P.S.
Один из самых клевых результатов даёт нажатие на крестик Закрыть программу.
И программа уже думает, что всё - уничтожает формы и данные, а ваш обработчик продолжает обращаться к этим формам и данным, ессно получая AV. Никаких ошибок - просто так задумано вами - программистом.
Метки delphi
Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 9
Комментарии
  1. Старый комментарий
    Аватар для Rius
    +100500
    Если в коде есть DoEvents (.Net Framework), processEvents (Qt Framework) или ProcessMessages (Delphi/C++ Builder), значит это говнокод и его надо переписать.
    Причём это не сами методы плохие, а их применение говорит о недостатке знания более правильных способов.
    Запись от Rius размещена 30.08.2017 в 07:14 Rius вне форума
  2. Старый комментарий
    Аватар для Avazart
    Если в коде есть
    Как правило да.
    Но теоретически можно написать код который будет работать нормально, другое дело что его написать довольно сложно при таком подходе и не оправдано.
    Запись от Avazart размещена 30.08.2017 в 12:58 Avazart вне форума
  3. Старый комментарий
    Аватар для krapotkin
    согласен-1.
    согласен-2.
    и даже написал, что само по себе это не приведет к чему-то плохому
    иногда это даже оправданный выход.
    но тестирование дураком эта архитектура уж точно не пройдет)))
    Запись от krapotkin размещена 30.08.2017 в 13:33 krapotkin вне форума
  4. Старый комментарий
    Аватар для Jin X
    С отдельным потоком дров можно наломать ещё больше. Тут есть дополнительные нюансы типа необходимости использования критических секций (иногда), проблемы взаимодействия с VCL (хотя значения из компонентов нужно читать заранее, а не из цикла). Да и так же, как и при использовании ProcessMessages, нужно отключать кнопки повторного запуска события (и другие сопутствующие) + обрабатывать CloseQuery (нужно же обрывать цикл потока через глобальную переменную или event [TThread.Terminate опасно, если FreeOnTerminate = True] и потом ещё ждать завершения потока)

    Другое дело, что дополнительный поток не будет "отвлекаться" на ProcessMessages и может отработать быстрее + (если ProcessMessages вызывается не на каждой итерации, а раз в секунду, скажем) не будет мелких "провисов"...

    Но будет не менее прикольно, когда закрытие формы завершит поток фактически через TerminateThread (в момент ExitProcess). И форма ведь закроется (*), и не будет AV, что создаст иллюзию, что код написан верно. Ещё будет забавно новичку искать ошибку, если иногда вдруг (скажем, раз в 10 запусков) будут возникать AV при закрытии формы. Например, когда поток будет обращаться к уже освободившемуся объекту.

    Вывод такой: любым инструментом нужно уметь правильно пользоваться. А просто сказать новичку: юзай потоки вместо ProcessMessages тоже не вариант...

    p.s.
    (*) А вот при цикле с ProcessMessages форма не закроется, тут вы ошибаетесь, программа не даст ей закрыться при нажатии на крестик (или при вызове Close), если только вы не открыли её через Show (без "Modal"), но и в этом случае она не уничтожится, а просто уйдёт в Hide.
    Запись от Jin X размещена 09.07.2018 в 22:47 Jin X на форуме
  5. Старый комментарий
    Аватар для Avazart
    С отдельным потоком дров можно наломать ещё больше.
    Если мозгов нет, то можно ничего не делая наломать и не только дров.
    Запись от Avazart размещена 09.07.2018 в 23:01 Avazart вне форума
  6. Старый комментарий
    Аватар для Jin X
    Если мозгов нет, то можно ничего не делая наломать и не только дров.
    А если есть, то и с ProcessMessages всё будет работать
    Я к тому, что нельзя говорить, что ProcessMessages – однозначно зло и говнокод, а потоки – благодать и признак мастерства. Для каждого случая свой инструмент, не так ли?
    Запись от Jin X размещена 09.07.2018 в 23:04 Jin X на форуме
  7. Старый комментарий
    Аватар для Rius
    А если есть, то и с ProcessMessages всё будет работать
    Новичкам это не грозит, т.к. никто из них не понимает очереди сообщений и непредусмотренного поведения от ProcessMessages.
    В справке Embarcadero даже ни слова нет о возможных проблемах, типа юзайте и будет вам счастье, вот же в простеньком "Hello World" всё наглядно показано. В Net Framework же предупреждают:
    Calling this method causes the current thread to be suspended while all waiting window messages are processed. If a message causes an event to be triggered, then other areas of your application code may execute. This can cause your application to exhibit unexpected behaviors that are difficult to debug. If you perform operations or computations that take a long time, it is often preferable to perform those operations on a new thread.
    В сложной программе это источник адовых багов, которые замаешься отлавливать, что в общем и есть говнокод.
    Поэтому заранее надо учить правильным методам, а не костылям.
    а потоки – благодать и признак мастерства
    Для новичков - признак движения к мастерству.
    Запись от Rius размещена 10.07.2018 в 05:58 Rius вне форума
  8. Старый комментарий
    Аватар для krapotkin
    Вот как раз новичку просто сказать не юзай ProcessMessages - это правильный вариант))
    не уничтожится, а просто уйдёт
    гы. там что только не понаворочают как раз на обработчики. программа либо будет сыпать AV, и это проверено )) либо так и останется висеть полуубитая, потому что уже некому разбирать очередь сообщений ))
    Запись от krapotkin размещена 10.07.2018 в 06:21 krapotkin вне форума
  9. Старый комментарий
    Аватар для Avazart
    А если есть, то и с ProcessMessages всё будет работать
    Не будет, а если и будет то через ... одним словом гавнокод

    Я к тому, что нельзя говорить, что ProcessMessages – однозначно зло и говнокод, а потоки – благодать и признак мастерства. Для каждого случая свой инструмент, не так ли?
    Но именно так и есть.
    В данном случае ProcessMessages не инструмент.

    ProcessMessages в коде следствие непонимание этого факта и оправдание что бы и далее не изучать многопоточность.

    Думаю есть случаи когда ProcessMessages уместен, но этих случаев очень мало, и большая часть из них банальная лень писать код по нормальному.
    Запись от Avazart размещена 10.07.2018 в 23:03 Avazart вне форума
 
Новые блоги и статьи
20. Мат мед. Абсентеизм как отдельный тип простоя
anaschu 29.05.2026
Апдейт модели: исправленные баги, абсентеизм и новые механизмы Продолжаю развивать ранее описанную модель рабочего коллектива на AnyLogic. За последние несколько дней был проведён серьёзный. . .
19. здоровье, усталость и психотип работника влияют на производительность предприятия, и наоборот, производительность на здоровье, усталось и психотип
anaschu 28.05.2026
Дискретно-событийная модель рабочего коллектива на AnyLogic: здоровье, выгорание, психотипы и микростимуляция Привет, коллеги. Хочу поделиться итогами нескольких недель работы над симуляционной. . .
"Прокси" для последовательного порта
Eddy_Em 28.05.2026
Эту штуку написал я достаточно давно. Но сейчас вот понадобилось настроить датчик грозы, но при этом не отключать его от "метеодемона". Соответственно, надо запустить этот "прокси": метеодемон будет. . .
Рефакторинг программы уравнивания.
Massaraksh7 26.05.2026
Пример по предыдущей записи в блоге. Но, надо заметить, что, во-первых, там оптимизация не только математики, но и работы с базой данных, и с графами, а во-вторых, это ещё не всё.
Использование TThread в Lazarus для математических вычислений.
Massaraksh7 25.05.2026
Производя рефакторинг своих программ на предмет ускорения их работы, обратил внимание на такой аспект, как сокращение времени матвычислений. Дело в том, что приходится работать с большими матрицами. . .
Модель здравосохранения 18. Чем здоровее работник, тем быстрее выгорает
anaschu 24.05.2026
Имитационная модель корпоративного здравоохранения: что показывает математика Сегодня в модели рабочего коллектива на AnyLogic появились три новые механики — выгорание через накопленную усталость,. . .
Модель здравосохранения 17. Планы на выгорание
anaschu 23.05.2026
Вот конкретная схема реализации: В классе Работник добавить: накопленнаяУсталость — растёт каждый час работы, снижается в перерывы и болезни коэффициентПрезентеизма — снижает продуктивность. . .
Изменение цветов в палитре gif файла aka фавикона
russiannick 23.05.2026
Изменение цветов в палитре gif файла, юзаемого как фавиконка в составе html-файла, помещенная в base64, средствами нативного Java Script, навеянное сном в майский день. Для работы необходим браузер,. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru