|
Многопоточное программирование в Delphi для начинающих
|
|||
---|---|---|---|
#18+
wadman didgik И что тогда использовать вместо Sleep? Например в WaitFor*Object, у которого в аргументах событие, которому можно посигналить извне. Не очень понятно извне это из основного потока? Повесить там таймер и раз, допустим, в 10 мин. посылать сигнал? ... |
|||
:
Нравится:
Не нравится:
|
|||
04.09.2020, 16:16 |
|
Многопоточное программирование в Delphi для начинающих
|
|||
---|---|---|---|
#18+
didgik А я вот не понял п4.1 Зачем Sleep() обертывать в WaitTimeout ? Можно и не обертывать. В данном случае поведение программы от этого не изменится. Однако действие по ожиданию таймаута может быть более сложным, чем просто вызвать Sleep. В этом случае разумнее вынести код в отдельную функцию. В дальнейшем можно улучшить код в данной функции, не переделывая все места, из которых эта функция вызывается. ... |
|||
:
Нравится:
Не нравится:
|
|||
04.09.2020, 16:55 |
|
Многопоточное программирование в Delphi для начинающих
|
|||
---|---|---|---|
#18+
didgik И что тогда использовать вместо Sleep? В некоторых случаях можно использовать более навороченную версию: ThreadWaitTimeout из модуля MTUtils.pas. Но в идеале следует использовать функцию WaitXXXXX ... |
|||
:
Нравится:
Не нравится:
|
|||
04.09.2020, 16:59 |
|
Многопоточное программирование в Delphi для начинающих
|
|||
---|---|---|---|
#18+
04.09.2020 16:59, DmSer пишет: > Но в идеале следует использовать функцию WaitXXXXX мотивируй Posted via ActualForum NNTP Server 1.5 ... |
|||
:
Нравится:
Не нравится:
|
|||
04.09.2020, 17:05 |
|
Многопоточное программирование в Delphi для начинающих
|
|||
---|---|---|---|
#18+
DmSer didgik И что тогда использовать вместо Sleep? В некоторых случаях можно использовать более навороченную версию: ThreadWaitTimeout из модуля MTUtils.pas. Но в идеале следует использовать функцию WaitXXXXX я, кстати, не нашел ThreadWaitTimeout в 2007. ... |
|||
:
Нравится:
Не нравится:
|
|||
04.09.2020, 17:10 |
|
Многопоточное программирование в Delphi для начинающих
|
|||
---|---|---|---|
#18+
Мимопроходящий 04.09.2020 16:59, DmSer пишет: > Но в идеале следует использовать функцию WaitXXXXX мотивируй Оверхед меньше по сравнению с sleep(10) в цикле. ... |
|||
:
Нравится:
Не нравится:
|
|||
04.09.2020, 17:56 |
|
Многопоточное программирование в Delphi для начинающих
|
|||
---|---|---|---|
#18+
didgik DmSer пропущено... В некоторых случаях можно использовать более навороченную версию: ThreadWaitTimeout из модуля MTUtils.pas. Но в идеале следует использовать функцию WaitXXXXX я, кстати, не нашел ThreadWaitTimeout в 2007. Там её нет. Искать нужно там же где статья. ... |
|||
:
Нравится:
Не нравится:
|
|||
04.09.2020, 18:10 |
|
Многопоточное программирование в Delphi для начинающих
|
|||
---|---|---|---|
#18+
didgik wadman пропущено... Например в WaitFor*Object, у которого в аргументах событие, которому можно посигналить извне. Не очень понятно извне это из основного потока? Повесить там таймер и раз, допустим, в 10 мин. посылать сигнал? Посылать сигнал только тогда, когда нужно. Будить таким образом поток, если нужно. А в Thread.Destroy сделать Terminate и SetEvent. А в потоке после ожидания проверять на Terminated. ... |
|||
:
Нравится:
Не нравится:
|
|||
04.09.2020, 20:56 |
|
Многопоточное программирование в Delphi для начинающих
|
|||
---|---|---|---|
#18+
DmSer Мимопроходящий 04.09.2020 16:59, DmSer пишет: > Но в идеале следует использовать функцию WaitXXXXX мотивируй Оверхед меньше по сравнению с sleep(10) в цикле. Помимо меньшего оверхеда также следует отметить время реакции. Поток, остановленный по команде Sleep, может возобновить работу только после срабатывания системного таймера. А по умолчанию системный таймер срабатывает примерно раз в 16 миллисекунд. При ожидании на WaitForXXXXX возобновление работы происходит намного оперативнее. Идеальный случай, когда в момент вызова SetEvent / ReleaseMutex у планировщика есть возможность запустить ожидающий поток на том же ядре и отсутствуют другие желающие, кому требуется это же ядро. Тогда планировщик запускает ожидающий поток немедленно, не прибегая к системному таймеру или к механизму асинхронного вызова APC. На всё про всё уходит порядка 6 микросекунд (железо не самое мощное). Однако такое происходит редко, чаще планировщик запускает ожидающий поток с использованием механизма APC (с программным прерыванием), в этом случае уходит от 20 до 50 микросекунд (на моих тестах). Худший случай, когда механизм APC не смог запустить ожидаемый поток (мог вклиниться поток с более высоким приоритетом), тогда запуск ожидающего потока будет запланирован уже по событию системного таймера. Как-то так оно работает (в моём понимании). ... |
|||
:
Нравится:
Не нравится:
|
|||
05.09.2020, 23:45 |
|
Многопоточное программирование в Delphi для начинающих
|
|||
---|---|---|---|
#18+
За последнее время: 1. Добавлен раздел "1.2 Можно ли избежать многопоточного программирования", к нему пример ExNotUseThreads 2. Добавлен раздел "Основные объекты синхронизации в Windows" 3. Добавлен раздел "7.1 Главный поток управляет работой дополнительного потока с помощью объекта "Event" (событие)" и к нему пример FastStopThread 4. Добавлен пример SimpleLogger, который очень наглядно демонстрирует преимущество использования доп. потока при записи в лог-файл (соответствующее описание к данному примеру пока отсутствует). 5. Исправлено несколько замечаний, в том числе большая часть замечаний от _Vasilisk_ 6. Учтены некоторые предложения ... |
|||
:
Нравится:
Не нравится:
|
|||
23.11.2020, 08:53 |
|
Многопоточное программирование в Delphi для начинающих
|
|||
---|---|---|---|
#18+
DmSer 1. Добавлен раздел "1.2 Можно ли избежать многопоточного программирования", к нему пример ExNotUseThreads ... |
|||
:
Нравится:
Не нравится:
|
|||
23.11.2020, 23:19 |
|
Многопоточное программирование в Delphi для начинающих
|
|||
---|---|---|---|
#18+
А я вот просто хочу выразить признательность автору статьи! От "не новичка" в Delphi, но неработающего с потоками (пока). Периодически читаю что-то о потоках, т.к. сегодня не надо, а завтра... Такая статья очень поможет если вдруг "припрёт". Прочитал весь топик. Начну читать статью... Еще раз - автору спасибо. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.12.2020, 18:19 |
|
Многопоточное программирование в Delphi для начинающих
|
|||
---|---|---|---|
#18+
Volk65 А я вот просто хочу выразить признательность автору статьи! От "не новичка" в Delphi, но неработающего с потоками (пока). Периодически читаю что-то о потоках, т.к. сегодня не надо, а завтра... Такая статья очень поможет если вдруг "припрёт". Прочитал весь топик. Начну читать статью... Еще раз - автору спасибо. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.12.2020, 20:29 |
|
Многопоточное программирование в Delphi для начинающих
|
|||
---|---|---|---|
#18+
Volk65 А я вот просто хочу выразить признательность автору статьи! От "не новичка" в Delphi, но неработающего с потоками (пока). Периодически читаю что-то о потоках, т.к. сегодня не надо, а завтра... Такая статья очень поможет если вдруг "припрёт". Прочитал весь топик. Начну читать статью... Еще раз - автору спасибо. Спасибо, буду рад, если мои труды принесут для кого-то пользу! Добавлены следующие новые разделы: 7.2 Использование объекта "Event" для разработки потока логгирования ... 7.3 Пара слов об объекте "Mutex" ... 7.4 Пара слов об объекте "Semaphore" ... 7.5 Критическая секция и монитор ... 7.6 Механизм синхронизации "много читателей и один писатель" (MREW) ... 8. Обработка исключений в дополнительных потоках ... ... |
|||
:
Нравится:
Не нравится:
|
|||
05.01.2021, 14:25 |
|
Многопоточное программирование в Delphi для начинающих
|
|||
---|---|---|---|
#18+
Добавлен пример использования TThreadedQueue https://github.com/loginov-dmitry/multithread/tree/master/ExQueue/ExThreadedQueue Комментарии есть в исходниках примера. В статье пока нет. ... |
|||
:
Нравится:
Не нравится:
|
|||
09.01.2021, 21:18 |
|
Многопоточное программирование в Delphi для начинающих
|
|||
---|---|---|---|
#18+
DmSer, а можете добавить примеров с описанием где и как можно применять CreateThread. Например как решение в топике: https://stackoverflow.com/questions/25949391/simple-tcp-connect-timeout-wrapper-in-delphi Либо можно сделать что-то аналогичное с помощью TThread? ... |
|||
:
Нравится:
Не нравится:
|
|||
04.03.2021, 09:51 |
|
Многопоточное программирование в Delphi для начинающих
|
|||
---|---|---|---|
#18+
Добавлены новые разделы: 9. Передача данных в дополнительный поток ... 9.1 Использование обычного списка (TList, TStringList, TThreadList) и периодический контроль списка ... 9.2 Использование обычного списка (TList, TStringList, TThreadList) и объекта Event ... 9.3 Использование очереди TThreadedQueue<T> (множество producer-потоков и один consumer-поток) ... 12. Работа с базой данных из дополнительного потока ... 13. Проблемы, возникающие при создании большого количество потоков ... В частности, содержимое п. 13: 1. Ограниченность адресного пространства. Сейчас практически никто не использует 32-разрядную ОС Windows. Если мы скомпилируем своё приложение в 32-битном режиме (с размером стека по умолчанию 1 МБ), запустим его в 64-битной ОС Windows и попытаемся создать 2000 потоков, то получим ошибку. Система не в состоянии создать более 1650 потоков. На каждый созданный поток Windows выделяет 1 МБ виртуальной памяти для 32-битного стека и 256 КБ виртуальной памяти для 64-битного стека (его Windows создаёт и поддерживает автоматически для обеспечения возможности работы 32-битных программ в 64-битной ОС). Насколько я понимаю, на размер 64-битного стека мы влиять не можем, но, если уменьшим размер виртуальной памяти под 32-битный стек (это можно сделать в окне Project / Options / Linker / Max stack size), то можем значительно увеличить максимальное количество потоков в приложении. При этом необходимо воздержаться от объявления локальных статических массивов с большим числом элементов. Данная проблема (с ограниченностью адресного пространства) актуальна только для 32-битных приложений. Если вы компилируете 64-битное приложение, то данной проблемы не существует. 2. Ограниченность физической памяти. Информация актуальна для 64-битной Windows и стандартного менеджера памяти (либо FastMM4). Один поток в 32-битной программе занимаем минимум 88 КБ ОЗУ. В 64-битной программе поток весит меньше - минимум 52 КБ ОЗУ (очевидно, экономия достигается за счёт того, что используется только один стек - 64-битный). Это значение не зависит от объёма виртуальной памяти, выделенной под стек. Учитывайте это, если планируете создавать огромное количество потоков! 3. Использование функции WinAPI-функции Sleep либо WaitForXXX для организации задержек в бесконечном цикле. Очень простое решение - реализовать в дополнительном потоке бесконечный цикл, периодически проверять значение какого-то флага (либо элемента в очереди), в зависимости от значения флага выполнять какое-либо действие, после чего переводить поток в спящий режим с помощью Sleep либо WaitForXXX. Если вы укажете время ожидания 1000 мс (или больше), то нет проблем (в том смысле, что нагрузка на процессор будет минимальной - примерно 50000 тактов в секунду при паузе в 1 секунду). Однако если Вы будете проверять значение флага каждые 10 миллисекунд, то нагрузка на процессор будет уже существенной - 2500000 тактов в секунду будет тратиться только на работу Sleep(10). Если у вас запущено 1000 таких потоков и каждый расходует 2500000 тактов в секунду, то будет обеспечена 100% загрузка одного ядра процессора (либо эта загрузка будет размазана по нескольким ядрам). Т.е. ваши 1000 потоков ещё не делают ничего полезного, но уже грузят процессор по полной программе! :) Для того, чтобы такой проблемы не было, не рекомендуется использовать Sleep либо WaitForXXX с маленькой задержкой. Гораздо лучше использовать WaitForXXX с большой задержкой (в том числе, INFINITY), а при изменении значения флага следует переводить объект ядра, который ожидает функция WaitForXXX, в сигнальное состояние. В этом случае потоки не будут тратить на контроль состояния флага практически никаких ресурсов процессора! 4. Использование TIdTCPServer для поддержания большого количества сетевых подключений. В древних версиях Indy10 вызовы Socket.ReadXXX приводили к высокой загрузке процессора. Приходилось их "разбавлять" с помощью Sleep(1) для снижения нагрузки на процессор. Такая же ситуация была с методом Socket.CheckForDataOnSource. Более того, раньше метод Socket.CheckForDataOnSource ещё и глючил - не возвращал управление, пока не закончится время ожидания, даже если пришли данные (поэтому приходилось его вызывать с минимальным таймаутом). Указанные проблемы приводили к созданию огромной нагрузке на процессор при большом количестве сетевых подключений. На данный момент в Indy10 эти проблемы решены. Актуальную версию Indy10 можно скачать с github, при этом она обычно работает c любой версией Delphi. Теперь методы ReadXXX и CheckForDataOnSource не создают никакой нагрузки на процессор и возвращают управление немедленно при появлении данных в сокете (в течение 100 микросекунд, если сервер и клиент запущены на одном компьютере). ... |
|||
:
Нравится:
Не нравится:
|
|||
05.04.2021, 10:06 |
|
Многопоточное программирование в Delphi для начинающих
|
|||
---|---|---|---|
#18+
К слову. Не нашел ни одного упоминания OnTerminate в коде. Хотя он бывает полезен для некоторых случаев. ... |
|||
:
Нравится:
Не нравится:
|
|||
05.04.2021, 10:52 |
|
Многопоточное программирование в Delphi для начинающих
|
|||
---|---|---|---|
#18+
makhaon К слову. Не нашел ни одного упоминания OnTerminate в коде. Хотя он бывает полезен для некоторых случаев. Я его не использовал, поэтому не стал про него ничего сочинять. Нужны какие-то удачные примеры использования. Технически это тот же Synchronize, только метод подсовывается снаружи, т.е. поток не привязан к какой-то конкретной форме. ... |
|||
:
Нравится:
Не нравится:
|
|||
05.04.2021, 11:20 |
|
Многопоточное программирование в Delphi для начинающих
|
|||
---|---|---|---|
#18+
Скорректирована информация по использованию TIdTCPServer ( ссылка ) Теперь информация изложена в следующем виде: 4. Неправильное использование компонента `TIdTCPServer`. При разработке TCP-серверов Delphi-программисты чаще всего используют компонент TIdTCPServer. При правильном использовании данный компонент может держать до 50000 подключений (существуют реальные примеры с таким количеством подключений). Разумеется, для этого программа должна быть 64-битной. Для поддержки 50000 подключений будет создано 50000 потоков и выделено около 3 ГБ ОЗУ, что весьма затратно. При таком количестве потоков ни в коем случае не должно быть циклов, в которых выполняется проверка чего-либо каждые 10 мс. Значение `Socket.ReadTimeout` должно быть не менее 10000 (10 секунд). При использовании `Socket.CheckForDataOnSource` для ожидания приёма данных от клиента также желательно использовать значение не менее 10000. **Внимание!** Перед каждым вызовом `Socket.CheckForDataOnSource` необходима проверка `if Socket.InputBuffer.Size = 0 then`, что обусловлено особенностями реализации метода `CheckForDataOnSource`. Если в буфере есть данные, то выполнять вызов `Socket.CheckForDataOnSource` не следует! **Информация!** Сами по себе данные в буфере `Socket.InputBuffer` появиться не могут. Появляются они там в следующих случаях: а) в контексте вызова метода `Socket.ReadXXX`, б) в контексте вызова метода `Socket.CheckForDataOnSource`, в) в момент подключения клиента к серверу, если клиент сразу же передал данные на сервер. **Информация!** На практике Delphi-программисту очень редко приходится разрабатывать TCP-сервер, способный держать 50000 соединений. Всё зависит от того, что именно делает TCP-сервер. Если он не выполняет какой-то особой обработки, а просто возвращает в ответ на запрос клиента текущее время (или иную информацию, которую не нужно запрашивать из базы данных или получать в результате сложных вычислений), то проблем никаких нет. Однако, если на каждый запрос приходится выполнять обращение к базе данных или производить сложные вычисления, то ресурсы сервера могут закончиться гораздо раньше (например, на 1000 соединений). В связи с этим рекомендую минимизировать количество обращений к базе данных и стараться держать всю необходимую информацию в памяти TCP-сервера, периодически обновляя её в фоновом потоке. **Внимание!** Не рекомендую использовать `TIdTCPServer` для решения задачи транзита данных. Данная задача отличается тем, что TCP-сервер не выполняет практически никакой обработки данных, а лишь передаёт клиенту "Б" данные, принятые от клиента "А" (и обратно). Если таких клиентов ("А" и "Б") будет 50000, то программа будет использовать около 3 ГБ ОЗУ. Загрузка процессора при активном обмене данными между клиентами будет также весьма приличной, поскольку при большом количестве потоков будет происходить очень много переключений контекста, а каждое переключение мы оцениваем в 50000 тактов. Существуют гораздо более удачные варианты решения задачи транзита данных: асинхронные сокеты и порты завершения ввода/вывода. И в том и в другом способе используется фиксированное количество потоков (например, 8 потоков для 4-ядерного процессора) и требуется намного меньше ОЗУ (как минимум, в 10 раз меньше, чем при использовании `TIdTCPServer`). Количество переключений контекста также намного меньше (сравнение имеет смысл производить только при высокой интенсивности обмена данными), т.к. за один квант времени поток сможет обработать данные, принятые от нескольких клиентов и передать данные нескольким клиентам. ... |
|||
:
Нравится:
Не нравится:
|
|||
04.06.2021, 19:45 |
|
Многопоточное программирование в Delphi для начинающих
|
|||
---|---|---|---|
#18+
автор т.к. за один квант времени поток сможет обработать данные, принятые от нескольких клиентов и передать данные нескольким клиентам. лучше: так как в одном потоке могут быть обработаны сразу множество соединений и нет необходимости переключать контекст. ... |
|||
:
Нравится:
Не нравится:
|
|||
05.06.2021, 10:56 |
|
Многопоточное программирование в Delphi для начинающих
|
|||
---|---|---|---|
#18+
makhaon автор т.к. за один квант времени поток сможет обработать данные, принятые от нескольких клиентов и передать данные нескольким клиентам. лучше: так как в одном потоке могут быть обработаны сразу множество соединений и нет необходимости переключать контекст. Хорошо, я поправлю. На самом деле я этот момент я не проверял. Рассчитываю на то, что если я ошибаюсь (ну может для асинхронных сокетов каждое событие генерирует переключение контекста), то знающие люди меня поправят :) Но надеюсь, что работает так, как я думаю (в том числе для портов завершения ввода-вывода). ... |
|||
:
Нравится:
Не нравится:
|
|||
05.06.2021, 23:06 |
|
Многопоточное программирование в Delphi для начинающих
|
|||
---|---|---|---|
#18+
Автору большой респект за огромный труд и низкий поклон от меня! Это не руководство для начинающих программистов, а скорее руководство для любых программистов, которые начинают писать многопоточные приложения на Delphi. Такую тему надо закреплять в шапке форума. Например, очень удобно сделано на форуме 4PDA, там весь важный материал в шапке на первой же странице. P.S. Зашел на ваш Github и с удивлением выяснил, что оказывается я давно уже использую ваш модуль LDSLogger. Спасибо большое за вашу библиотеку, работает безотказно, несмотря сильное развитие возможностей языка Delphi в последних версиях Embarcadero Delphi. ... |
|||
:
Нравится:
Не нравится:
|
|||
07.06.2021, 13:27 |
|
Многопоточное программирование в Delphi для начинающих
|
|||
---|---|---|---|
#18+
Benten, спасибо за столь высокую оценку моих трудов. Добавлен новый раздел : Выполнение длительной операции в дополнительном потоке с отображением информационного модального окна, блокирующего работу пользователя с программой. Ссылка на пример пример (проверял в D2007 и 10.4) Вводная часть: При разработке приложения очень часто, в ответ на действия пользователя, приходится запускать на выполнение код, длительность которого может составить несколько секунд, при этом должен устанавливаться запрет на дальнейшие действия пользователя с программой, до тех пор, пока длительный код не завершит свою работу. С такими ситуациями мы встречаемся очень часто, например: при нажатии кнопки выполняем запрос к базе данных, а затем показываем пользователю результат запроса в новом окне; выполняем операцию с банковской картой; выполняем пробитие чека на кассе; выполняем формирование отчёта; отображаем на экране окно, которое в событии FormCreate выполняет длительную загрузку данных (из файла или из базы данных); сохраняем изменения, внесённые в документ; и т.д. Во всех случаях пользователю необходимо дождаться, пока операция не будет завершена. Пока операция выполняется, использование программы является бессмысленным. Более того, если мы возьмём, и просто запустим выполнение длительной операции в дополнительном потоке, не блокируя интерфейс пользователя, то пользователь может нажать что-нибудь лишнее, в результате чего программа может перейти в непредсказуемое состояние. При таком способе запуска длительной операции, для блокировки интерфейса пользователя рекомендуется выставить свойство Enabled := False для всех элементов, с которыми пользователь может взаимодействовать с помощью мыши либо клавиатуры, а также запретить закрытие окна (с помощью параметра CanClose в обработчике FormCloseQuery). Конечно, вы можете запустить длительный код в контексте основного потока. При этом пользователь не сможет ничего лишнего нажать до завершения операции (не забудьте изменить текст нажатой кнопки и курсор мыши на время выполнения операции - так пользователь будет хотябы понимать, что программа отреагировала на его действие и чем-то занимается). Если операция выполняется несколько секунд без какого-либо информирования пользователя, то пользоваться такой программой будет неприятно. Ещё хуже, если Windows повесит собственное окно с надписью "не отвечает" - в этом случае у пользователя может сложиться впечатление, что программа зависла. Если программа находится в таком состоянии более 30 секунд, то с большой вероятностью пользователь может попытаться решить "проблему" кардинально с помощью диспетчера задач либо путём перезагрузки компьютера. Вы можете перед началом длительной операции отобразить на экране дополнительное окно к надписью "Выполняется операция ХХХ. Ждите!", а в конце операции закрыть его (см п. 1.2). Однако при таком способе есть несколько минусов: Невозможно отобразить прошедшее время выполнения операции; Windows может навесить собственное окно с надписью "Не отвечает", после чего возможна проблема с "вылетом" текущего окна на задний план (в этом случае пользователь не сможет ничего нажать в окне, которое находится на переднем плане и может принять кардинальное решение о перезагрузке компьютера); В программе не работают никакие автоматические операции, запускающиеся из основного потока (обработчик TTimer.OnTimer не будет вызываться, пока основной поток не освободится); Основной поток не обрабатывает вызовы SendMessage, PostMessage, Synchronize, Queue; Если в программе используются асинхронные сетевые компоненты, использующие основной поток (например, Overbyte ICS), то их работа будет приостановлена, а соединения могут быть разорваны; Сложно организовать информирование пользователя о текущем состоянии выполняемой операции; Невозможно прервать ход выполнения длительной операции, даже если прерывание операции логично и не приводит к каким-либо проблемам (например, при формировании отчёта). Далее демонстрируется пример, в котором все перечисленные проблемы решены! По сути, это готовое решение, котором можно использовать практически в любом VCL-проекте. Но мне хотелось бы, чтобы читатель досконально разобрался с исходными кодами. Мною было потрачено на этот пример много дней и весь код я постарался привести в максимально читабельный вид. Также мною разработан модуль ParamsUtils.pas, который значительно упрощает передачу именованного списка параметров различного типа, что весьма полезно в ситуации, когда мы не можем напрямую вызвать целевую функцию с её "родными" параметрами. В папке ExWaitWindow находится пример, в котором демонстрируется способ отображения дополнительного модального окна при запуске длительной операции с помощью функции DoOperationInThread. Ниже пример использования функции DoOperationInThread: procedure TMainForm.Button3Click(Sender: TObject); begin DoOperationInThread(Self, OPERATION_TYPE_NONE, 'Длительные вычисления', TParamsRec.Build(['Min', 300, 'Max', 700]), ProgressOperation, NEED_SHOW_STOP_BTN); end; В данном примере на экране отображается модальное окно с надписью "Длительные вычисления". Данное окно отображается на экране около 5 секунд. В этом окне отображаются следующие элементы: Время, прошедшее от начала операции; Полоса ProgressBar, которая индицирует ход вычислений; Текущее значение, используемое в вычислительном алгоритме; Границы вычисления Min и Max; Кнопка "Отмена", позволяющая досрочно прервать выполнение операции. ⚠️ Внимание! Обратите внимание, что длительная операция запускается в дополнительном потоке! ... |
|||
:
Нравится:
Не нравится:
|
|||
09.07.2021, 14:58 |
|
Многопоточное программирование в Delphi для начинающих
|
|||
---|---|---|---|
#18+
DmSer Добавлен новый раздел : Выполнение длительной операции в дополнительном потоке с отображением информационного модального окна, блокирующего работу пользователя с программой. Респект! Полезная фича, действительно. ... |
|||
:
Нравится:
Не нравится:
|
|||
09.07.2021, 17:25 |
|
|
start [/forum/topic.php?fid=58&msg=40034473&tid=2036872]: |
0ms |
get settings: |
18ms |
get forum list: |
6ms |
check forum access: |
1ms |
check topic access: |
1ms |
track hit: |
46ms |
get topic data: |
3ms |
get forum data: |
1ms |
get page messages: |
605ms |
get tp. blocked users: |
0ms |
others: | 2467ms |
total: | 3148ms |
0 / 0 |