Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
Топик располагается на нескольких страницах: Ctrl  назад   1 2 3 4 5 [6]      все
 Re: Многопоточное программирование в Delphi для начинающих  [new]
didgik
Member

Откуда:
Сообщений: 967
wadman
didgik
И что тогда использовать вместо Sleep?

Например в WaitFor*Object, у которого в аргументах событие, которому можно посигналить извне.


Не очень понятно извне это из основного потока? Повесить там таймер и раз, допустим, в 10 мин. посылать сигнал?
4 сен 20, 16:16    [22192204]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1347
didgik
А я вот не понял п4.1
Зачем Sleep() обертывать в WaitTimeout ?


Можно и не обертывать. В данном случае поведение программы от этого не изменится. Однако действие по ожиданию таймаута может быть более сложным, чем просто вызвать Sleep. В этом случае разумнее вынести код в отдельную функцию. В дальнейшем можно улучшить код в данной функции, не переделывая все места, из которых эта функция вызывается.
4 сен 20, 16:55    [22192223]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1347
didgik

И что тогда использовать вместо Sleep?


В некоторых случаях можно использовать более навороченную версию: ThreadWaitTimeout из модуля MTUtils.pas.

Но в идеале следует использовать функцию WaitXXXXX
4 сен 20, 16:59    [22192225]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Мимопроходящий
Member

Откуда: бурятский тундрюк, эсквайр
Сообщений: 32193

04.09.2020 16:59, DmSer пишет:
> Но в идеале следует использовать функцию WaitXXXXX

мотивируй

Posted via ActualForum NNTP Server 1.5

4 сен 20, 17:05    [22192229]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
didgik
Member

Откуда:
Сообщений: 967
DmSer
didgik

И что тогда использовать вместо Sleep?


В некоторых случаях можно использовать более навороченную версию: ThreadWaitTimeout из модуля MTUtils.pas.

Но в идеале следует использовать функцию WaitXXXXX

я, кстати, не нашел ThreadWaitTimeout в 2007.
4 сен 20, 17:10    [22192233]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1347
Мимопроходящий

04.09.2020 16:59, DmSer пишет:
> Но в идеале следует использовать функцию WaitXXXXX

мотивируй


Оверхед меньше по сравнению с sleep(10) в цикле.
4 сен 20, 17:56    [22192257]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1347
didgik
DmSer
пропущено...


В некоторых случаях можно использовать более навороченную версию: ThreadWaitTimeout из модуля MTUtils.pas.

Но в идеале следует использовать функцию WaitXXXXX

я, кстати, не нашел ThreadWaitTimeout в 2007.


Там её нет. Искать нужно там же где статья.
4 сен 20, 18:10    [22192266]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
YuRock
Member

Откуда: Донецк
Сообщений: 4522
didgik
wadman
пропущено...

Например в WaitFor*Object, у которого в аргументах событие, которому можно посигналить извне.


Не очень понятно извне это из основного потока? Повесить там таймер и раз, допустим, в 10 мин. посылать сигнал?
Из любого потока.
Посылать сигнал только тогда, когда нужно. Будить таким образом поток, если нужно.
А в Thread.Destroy сделать Terminate и SetEvent. А в потоке после ожидания проверять на Terminated.
4 сен 20, 20:56    [22192307]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1347
DmSer
Мимопроходящий

04.09.2020 16:59, DmSer пишет:
> Но в идеале следует использовать функцию WaitXXXXX

мотивируй


Оверхед меньше по сравнению с sleep(10) в цикле.


Помимо меньшего оверхеда также следует отметить время реакции.

Поток, остановленный по команде Sleep, может возобновить работу только после срабатывания системного таймера. А по умолчанию системный таймер срабатывает примерно раз в 16 миллисекунд.

При ожидании на WaitForXXXXX возобновление работы происходит намного оперативнее.

Идеальный случай, когда в момент вызова SetEvent / ReleaseMutex у планировщика есть возможность запустить ожидающий поток на том же ядре и отсутствуют другие желающие, кому требуется это же ядро. Тогда планировщик запускает ожидающий поток немедленно, не прибегая к системному таймеру или к механизму асинхронного вызова APC. На всё про всё уходит порядка 6 микросекунд (железо не самое мощное).
Однако такое происходит редко, чаще планировщик запускает ожидающий поток с использованием механизма APC (с программным прерыванием), в этом случае уходит от 20 до 50 микросекунд (на моих тестах).
Худший случай, когда механизм APC не смог запустить ожидаемый поток (мог вклиниться поток с более высоким приоритетом), тогда запуск ожидающего потока будет запланирован уже по событию системного таймера.
Как-то так оно работает (в моём понимании).
5 сен 20, 23:45    [22192613]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1347
За последнее время:
1. Добавлен раздел "1.2 Можно ли избежать многопоточного программирования", к нему пример ExNotUseThreads
2. Добавлен раздел "Основные объекты синхронизации в Windows"
3. Добавлен раздел "7.1 Главный поток управляет работой дополнительного потока с помощью объекта "Event" (событие)" и к нему пример FastStopThread
4. Добавлен пример SimpleLogger, который очень наглядно демонстрирует преимущество использования доп. потока при записи в лог-файл (соответствующее описание к данному примеру пока отсутствует).
5. Исправлено несколько замечаний, в том числе большая часть замечаний от _Vasilisk_
6. Учтены некоторые предложения
23 ноя 20, 08:53    [22236930]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Sapersky
Member

Откуда:
Сообщений: 86
DmSer
1. Добавлен раздел "1.2 Можно ли избежать многопоточного программирования", к нему пример ExNotUseThreads
Про псевдо-многопоточность я бы ещё написал, что можно прятать умеренные по времени задержки (до 0.5 с) в OnIdle. OnIdle срабатывает, когда нет новых сообщений окну, в частности когда пользователь перестаёт тыкать в клавиатуру/мышь. То есть можно отложить относительно длительные действия на периоды неактивности пользователя.
23 ноя 20, 23:19    [22237549]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
Volk65
Member

Откуда:
Сообщений: 64
А я вот просто хочу выразить признательность автору статьи!
От "не новичка" в Delphi, но неработающего с потоками (пока). Периодически читаю что-то о потоках, т.к. сегодня не надо, а завтра... Такая статья очень поможет если вдруг "припрёт".
Прочитал весь топик. Начну читать статью... Еще раз - автору спасибо.
1 дек 20, 18:19    [22241017]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
white_nigger
Member

Откуда: Тула
Сообщений: 2509
Volk65
А я вот просто хочу выразить признательность автору статьи!
От "не новичка" в Delphi, но неработающего с потоками (пока). Периодически читаю что-то о потоках, т.к. сегодня не надо, а завтра... Такая статья очень поможет если вдруг "припрёт".
Прочитал весь топик. Начну читать статью... Еще раз - автору спасибо.
А классику "Multithreading – The Delphi Way" уже прочитал? )) Имхо лучшее для "не новичка"
1 дек 20, 20:29    [22241088]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1347
Volk65
А я вот просто хочу выразить признательность автору статьи!
От "не новичка" в Delphi, но неработающего с потоками (пока). Периодически читаю что-то о потоках, т.к. сегодня не надо, а завтра... Такая статья очень поможет если вдруг "припрёт".
Прочитал весь топик. Начну читать статью... Еще раз - автору спасибо.


Спасибо, буду рад, если мои труды принесут для кого-то пользу!

Добавлены следующие новые разделы:

7.2 Использование объекта "Event" для разработки потока логгирования ...

7.3 Пара слов об объекте "Mutex" ...

7.4 Пара слов об объекте "Semaphore" ...

7.5 Критическая секция и монитор ...

7.6 Механизм синхронизации "много читателей и один писатель" (MREW) ...

8. Обработка исключений в дополнительных потоках ...
5 янв 21, 14:25    [22258937]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1347
Добавлен пример использования TThreadedQueue
https://github.com/loginov-dmitry/multithread/tree/master/ExQueue/ExThreadedQueue

Комментарии есть в исходниках примера. В статье пока нет.
9 янв 21, 21:18    [22260791]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
destroyer86
Member

Откуда:
Сообщений: 2
DmSer, а можете добавить примеров с описанием где и как можно применять CreateThread.
Например как решение в топике: https://stackoverflow.com/questions/25949391/simple-tcp-connect-timeout-wrapper-in-delphi
Либо можно сделать что-то аналогичное с помощью TThread?

Сообщение было отредактировано: 4 мар 21, 09:47
4 мар 21, 09:51    [22289448]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1347
Добавлены новые разделы:

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 микросекунд, если сервер и клиент запущены на одном компьютере).
5 апр 21, 10:06    [22304221]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
makhaon
Member

Откуда: A galaxy far far away
Сообщений: 3826
К слову. Не нашел ни одного упоминания OnTerminate в коде. Хотя он бывает полезен для некоторых случаев.

Сообщение было отредактировано: 5 апр 21, 10:51
5 апр 21, 10:52    [22304257]     Ответить | Цитировать Сообщить модератору
 Re: Многопоточное программирование в Delphi для начинающих  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1347
makhaon
К слову. Не нашел ни одного упоминания OnTerminate в коде. Хотя он бывает полезен для некоторых случаев.


Я его не использовал, поэтому не стал про него ничего сочинять. Нужны какие-то удачные примеры использования. Технически это тот же Synchronize, только метод подсовывается снаружи, т.е. поток не привязан к какой-то конкретной форме.
5 апр 21, 11:20    [22304284]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: Ctrl  назад   1 2 3 4 5 [6]      все
Все форумы / Delphi Ответить