Как правильно останавливать потоки (TThread) ?

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Re: Как правильно останавливать потоки (TThread) ?

Сообщение olegy123 » 04.10.2017 10:54:44

Alex2013 писал(а):1 Мне тоже не нравится способ ожидания завершения через "тупой while" даже с ProcessMessages для профилактики дедлока..
ProcessMessages создан для того чтобы в главном потоке, когда он выполняет тяжелую пользовательскую, как правило в цикле, задачу можно было оживить оконное приложение - чтобы прорисовал счетчик или показал уровень загрузки.
Для обычного пользователя, который не знает что такое TThread..

Alex2013 писал(а):3 Использование PostMessage разумеется хорошая идея (Можно будет прорисовку результата поиска вызвать )
У меня было реализована подгрузка данных из базы данных в отдельном потоке. При этом пользователь спокойно мог работать с формой. Когда поток загрузил данные - послал на форму PostMessage - загрузка произведена - нужно обновить контрол.
Тем самым я избавился от синхронизации(мьютекс - блокировок) с главным потоком вообще..

Добавлено спустя 4 минуты 2 секунды:
Alex2013 писал(а)://(Можно и без Suspend; но зачем оставлять бесконечно крутится даже одну проверку флага ? )

Я бы залочил TEvent-ом..

Добавлено спустя 42 секунды:
Иногда нужно лочить на время.. типа если за это время ничего не произошло.. выходить с признаком TimeOut

Добавлено спустя 1 час 16 минут 34 секунды:
TEvent.WaitFor(Timeout : Cardinal) -> TWaitResult=(wrSignaled, wrTimeout, wrAbandoned, wrError);
olegy123
долгожитель
 
Сообщения: 1643
Зарегистрирован: 25.02.2016 12:10:20

Re: Как правильно останавливать потоки (TThread) ?

Сообщение Alex2013 » 04.10.2017 23:32:40

wadman писал(а):
Alex2013 писал(а):Ну и как тут событие обработать ? ВНУТРИ обработчика CheckBoxChange .... Ага !

Внутри обработчика нужно запустить поток, а в обработчике, который ловит окончание работы потока - остальное.

Гениально! 8) Вот только у меня часть данных "гарантированно локальные" (актуальны в рамках одного кадра и более того существуют и доступны только в конкретной части "конвейера " )...
Обработчик включения/выключения функции может блокировать или разблокировать часть настроек но запускать поток можно только изнутрии "конвейера" ...

Просто дело в том, что программа у меня и без использования TThread далеко не одномерная многое исполняется параллельно или как минимум пытается работать с данными в "условно реальном времени" .

Так что "одно-поточная линейная" или даже "двухмерная" логика управления событиями там не очень проходит ... :idea:

(Это я в своем квазиз-векторном редакторе мог быть точно уверен , что основные данные доступны ВСЕ время и любой "левый" обработчик (например обработчик операции undo/redo) в любой момент получит нужные данные и сумеет их верно обработать и выдать результат не опасаясь попасть "не в свое время" )

А поток добавляет еще одно "измерение" .
Ага, как там ? "ты все еще не умеешь думать в четырех измерениях! " :idea: 8)
Я тоже не умею... :roll: но хотя-бы попытаться можно ! :idea:

Добавлено спустя 47 минут 25 секунд:
olegy123 писал(а):
Alex2013 писал(а):1 Мне тоже не нравится способ ожидания завершения через "тупой while" даже с ProcessMessages для профилактики дедлока..
ProcessMessages создан для того чтобы в главном потоке, когда он выполняет тяжелую пользовательскую, как правило в цикле, задачу можно было оживить оконное приложение - чтобы прорисовал счетчик или показал уровень загрузки.
Для обычного пользователя, который не знает что такое TThread..

Знать то знают многие, но обычно использование TThread это как "глушение рыбы атомной бомбой" ... :idea:
Alex2013 писал(а):3 Использование PostMessage разумеется хорошая идея (Можно будет прорисовку результата поиска вызвать )
У меня было реализована подгрузка данных из базы данных в отдельном потоке. При этом пользователь спокойно мог работать с формой. Когда поток загрузил данные - послал на форму PostMessage - загрузка произведена - нужно обновить контрол.
Тем самым я избавился от синхронизации(мьютекс - блокировок) с главным потоком вообще..

Мне это метод не вполне подходит по причине попытки работать с данными в реальном времени .


Добавлено спустя 4 минуты 2 секунды:
Alex2013 писал(а)://(Можно и без Suspend; но зачем оставлять бесконечно крутится даже одну проверку флага ? )

Я бы залочил TEvent-ом..

Это как ? Организовать ожидание события внутри TMyThread.Execute; ? Чем это от моего метода ожидания флага UPDATE отличается ?

Добавлено спустя 42 секунды:
Иногда нужно лочить на время.. типа если за это время ничего не произошло.. выходить с признаком TimeOut

Ну да ... это как с Terminate поток повторно не запускается ...
А мне нужен режим горячего "подхвата данных" ... Краткий алгоритм такой "Каждые N-кадров проверять : Данные готовы? -> Поток готов их принять ? -->Клонировать данные --> Запустить обработку !( UPDATE :=True ) " (А результат независимо выводится по его готовности в другой части "конвейера кадров " )

А проблема "не своевременности" есть только при ручном выключении функции поиска метки и что-бы вызывать глюк нужно было очень быстро переключать галки настроек ...


Добавлено спустя 1 час 16 минут 34 секунды:
TEvent.WaitFor(Timeout : Cardinal) -> TWaitResult=(wrSignaled, wrTimeout, wrAbandoned, wrError);

А тут если можно подробнее.. :idea:
С этой частью функционала ТThread я пока не разобрался.
Alex2013
долгожитель
 
Сообщения: 2923
Зарегистрирован: 03.04.2013 11:59:44

Re: Как правильно останавливать потоки (TThread) ?

Сообщение olegy123 » 05.10.2017 10:22:12

Alex2013 писал(а):Это как ? Организовать ожидание события внутри TMyThread.Execute; ? Чем это от моего метода ожидания флага UPDATE отличается ?

Атомарностью на уровне ядра. Само ядро будет блокировать ход процесса, до того как не разрешится ситуация..
Я вот пишу под Rasspbery Pi свой плеер, с аппаратной декодированием. Объем буфера в модуле декодирования примерно 8Мб они делатся на 21буфер. Чтобы мне загрузить туда видео в 4Gб мне нужно много раз грузить.. Модуль имеет свое время декодирования которое я не знаю. По спецификации я должен подключить модуль таймера, планировщика, звук, и отрисовку.. но не сразу воткнуть, а когда модуле декодирования настроит сам у себя выходные буфера.. И их стунелить.. вот чтобы это все работало нужны блокировочки, а где то взаимные.. Где то нужно выполнить десятки гарантированных команд - где само ядро гарантирует что другие потоки в это время будут припаркованны.

Добавлено спустя 5 минут 35 секунд:
нет, кончено можно эмулировать блокировку на высоком уровне..
while Flag do ..
но жди загрузку процессора на все 100%.. А когда их у тебя более 2х- то 200%..
А у меня при рендеринге EGL и еще более 5 потоков.. не более 2%~8% загрузки CPU.. это с проигрыванием видео в HD качестве. Чувствуешь разницу..
Последний раз редактировалось olegy123 05.10.2017 11:03:38, всего редактировалось 1 раз.
olegy123
долгожитель
 
Сообщения: 1643
Зарегистрирован: 25.02.2016 12:10:20

Re: Как правильно останавливать потоки (TThread) ?

Сообщение wadman » 05.10.2017 10:35:20

Alex2013 писал(а):Гениально! Вот только у меня часть данных "гарантированно локальные" (актуальны в рамках одного кадра и более того существуют и доступны только в конкретной части "конвейера " )...
Обработчик включения/выключения функции может блокировать или разблокировать часть настроек но запускать поток можно только изнутрии "конвейера" ...

Это не проблема. Но желание г-кодить ломать не буду. Это исключительно личное дело. Удачи!
wadman
постоялец
 
Сообщения: 122
Зарегистрирован: 18.10.2016 15:54:28

Re: Как правильно останавливать потоки (TThread) ?

Сообщение olegy123 » 05.10.2017 10:57:56

Alex2013 писал(а):Ну да ... это как с Terminate поток повторно не запускается ...
TEvent - это шлагбаум, барьер, светофор с двумя состояниями (красный/зеленный) для процесса.. а другой процесс может переключать.
это не опция к TThread.
Типа твой любимый Suspend только не вырубающий где попало.. а в определенном для тебя месте.
olegy123
долгожитель
 
Сообщения: 1643
Зарегистрирован: 25.02.2016 12:10:20

Re: Как правильно останавливать потоки (TThread) ?

Сообщение serbod » 05.10.2017 12:12:06

olegy123 писал(а):TEvent - это шлагбаум, барьер, светофор

Я его называю "разрешающий семафор". Когда он выключен ResetEvent(), то WaitFor() задерживает выполнение до включения SetEvent().
Аватара пользователя
serbod
постоялец
 
Сообщения: 449
Зарегистрирован: 16.09.2016 11:03:02
Откуда: Минск

Re: Как правильно останавливать потоки (TThread) ?

Сообщение Alex2013 » 09.10.2017 00:48:25

serbod писал(а):olegy123 писал(а):
TEvent - это шлагбаум, барьер, светофор

Я его называю "разрешающий семафор". Когда он выключен ResetEvent(), то WaitFor() задерживает выполнение до включения SetEvent().

Ок ... Спасибо "буду посмотреть" ! :D
Зы
wadman писал(а):Это не проблема...

Разумеется , более того c легкостью признаю что в том виде, что есть сейчас это не просто "г-код" а вообще "УГ-код"... :oops: :wink: Метод PaintBox1Paint занимает уже чуть меньше 1000 строк (23кб) (Мой опыт говорит, что любой метод в классе формы не должен быть не больше 200-300 строк иначе выходит "гюкодром немереный" бо элементарно "заблудится" просто )

Но ради интереса как можно ЧИСТО ЛОГИЧЕСКИ сделать "классическую реакцию на событие" в произвольный момент времени даже при условно параллельной обработке в "квази реальном времен " ? (Данные не ждут, код не останавливается... это как пытаться по кнопке рисовать ход некой воображаемой "милисекундной стрелки" , там когда бы не нажал стрелка будет прорисована в СЛУЧАЙНОМ месте... или еще круче допустим опять же "по кнопке" пытаться отловить ее определенное положение "на девять часов " ... ИМХО совершенно бессмысленное занятие ! ) :idea:

...и как можно организовать обработку непрерывного потока кадров иначе чем "конвейером " ?
(Понятное дело по хорошему нужно сделать все значительно более структурировано чем это сделано сейчас но суть останется та же : Условия запуска и этапы обработки выстроенные в "конвейер" куда нужно встроить "снятие данных" для запуска (и сам запуск ) параллельного потока ... (пробовал с ходу представить возможный "обход" и понял, что бред выйдет полнейший ) )
Alex2013
долгожитель
 
Сообщения: 2923
Зарегистрирован: 03.04.2013 11:59:44

Re: Как правильно останавливать потоки (TThread) ?

Сообщение wadman » 09.10.2017 12:58:59

Alex2013 писал(а):...и как можно организовать обработку непрерывного потока кадров иначе чем "конвейером " ?

Сообщения потоку тоже обрабатываются ровно в том порядке, в каком их отправляешь.
Абсолютно ровно так же как и код кнопки в порядке сообщений о нажатии.

То есть нажатие кнопки = сообщение, разбудить поток = сообщение, поток своим сообщением сигнализирует об окончании своей работы и либо ожидает новую команду, либо обрабатывает очередное сообщение.
Обработчик кнопки работает в своем потоке, как ни странно, и со своей очередью сообщений.
Просто нужно вынести часть его работы в другой поток с другой очередью сообщений.
wadman
постоялец
 
Сообщения: 122
Зарегистрирован: 18.10.2016 15:54:28

Re: Как правильно останавливать потоки (TThread) ?

Сообщение olegy123 » 10.10.2017 18:44:20

Alex2013 писал(а):..и как можно организовать обработку непрерывного потока кадров иначе чем "конвейером " ?

Конвейер дает последовательность.
можно попробовать "хаус" - гонки на выживания.
olegy123
долгожитель
 
Сообщения: 1643
Зарегистрирован: 25.02.2016 12:10:20

Re: Как правильно останавливать потоки (TThread) ?

Сообщение Alex2013 » 10.10.2017 23:33:41

wadman писал(а):
Alex2013 писал(а):...и как можно организовать обработку непрерывного потока кадров иначе чем "конвейером " ?

Сообщения потоку тоже обрабатываются ровно в том порядке, в каком их отправляешь.
Абсолютно ровно так же как и код кнопки в порядке сообщений о нажатии.

Гм это нужно обдумать ...
То есть пока сообщение не обработано следующие не пройдет ?
Не плохо, хотя у меня уже есть небольшая проблема с пропуском "хода" (то что поток может оказаться занят когда приходит время загрузки данных это понятно, а вот то что счетчик кадров при этом должен снова прокутить ВЕСЬ интервал уже немного неприятно, но разумеется "лечится" его временной остановкой ...)
:idea: НО представь что "воздухе" повисла целая очередь запросов-сообщений обрабатываемых "по завершении предыдущей обработки" ... И как коду разгрести очередь если в основном потоке перерисовка с конвейером обработки в лучшем случае вызывается по таймеру ?( Кроме того я могу например банально окно подвигать или изменить его размер или вызвать обновление не по таймеру, а из "прерывания" от камеры.... )


То есть нажатие кнопки = сообщение, разбудить поток = сообщение, поток своим сообщением сигнализирует об окончании своей работы и либо ожидает новую команду, либо обрабатывает очередное сообщение.
Обработчик кнопки работает в своем потоке, как ни странно, и со своей очередью сообщений.
Просто нужно вынести часть его работы в другой поток с другой очередью сообщений.

Брр... Запутался ....
Как можно "в другой поток с другой очередью сообщений" предать нажатие кнопки или момент изменение состояния галки CheckBox-са из CheckBoxХХХChange ? "А не слишком ли я много чая пью ?" То бишь, зачем два уровня сообщений если одного хватает ?
... :roll:
Хотя если подумать в CheckBoxХХХChange можно однократно проверив флаг подождать СООБЩЕНИЯ из потока ! :idea:
О это действительно мысль !

Добавлено спустя 39 минут 26 секунд:
olegy123 писал(а):
Alex2013 писал(а):..и как можно организовать обработку непрерывного потока кадров иначе чем "конвейером " ?

Конвейер дает последовательность.
можно попробовать "хаус" - гонки на выживания.


Это как ? Куча фильтров и обработчиков вызывается "в произвольном прядке " (и того хуже в параллельных потоках )
каждый что-то делает и читает СВОЙ вход и пишет на СВОЙ выход ?
(В надежде что исходные данные актуальны и данные с выхода тоже будут подхвачены вовремя ? )
Действительно "хаус" ! :idea: :mrgreen:
Alex2013
долгожитель
 
Сообщения: 2923
Зарегистрирован: 03.04.2013 11:59:44

Re: Как правильно останавливать потоки (TThread) ?

Сообщение serbod » 11.10.2017 11:43:38

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

В случае параллельной обработки кадров (например, при онлайн-вещании в несколько потоков для разных типов устройств) кадры обрабатываются с разной скоростью и скапливаются в принимающем буфере, откуда вынимаются по таймеру в порядке отметки времени кадра. Опоздавшие кадры выкидываем, преждевременные оставляем до следующего тика таймера.
Аватара пользователя
serbod
постоялец
 
Сообщения: 449
Зарегистрирован: 16.09.2016 11:03:02
Откуда: Минск

Пред.

Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 33

Рейтинг@Mail.ru