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

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

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

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

Сообщение vitaly_l » 02.10.2017 20:18:03

Alex2013 писал(а):application.ProcessMessages; потоки (TThread) ?

Сливочное масло, намазывается на сливочное масло.
Alex2013 писал(а):вдруг я вообще чего-то элементного не учитываю ?

Я не очень понимаю в программировании, а тем более, что именно там у Вас происходит,
однако ProcessMessages в Thread - мне кажется лишним маслом, на масле.
Аватара пользователя
vitaly_l
долгожитель
 
Сообщения: 3333
Зарегистрирован: 31.01.2012 16:41:41

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

Сообщение Alex2013 » 02.10.2017 21:11:55

Я не очень понимаю в программировании, а тем более, что именно там у Вас происходит,
однако ProcessMessages в Thread - мне кажется лишним маслом, на масле.


Когда дело было в поиске контуров и я сам "заранее согласился с вашим мнением " :wink: и отказался от использования TThread
(Мне для отладки рекурсивной процедуры нужна была возможность создать "стороннего наблюдателя " а после отладки это был просто лишний тормоз )

Но при поиске (распознавании) метки, все иначе и использование TThread полностью себя оправдало . :idea:

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

Дело в том, что процесс поиска реально можно запустить "параллельной ниткой " избавившись от ВИДИМОГО (нервы драло невероятно !) замирания обработки кадров (он у меня и так вызывается не для каждого кадра но без отдельного потока это не очень помогает )То есть я кидаю в процесс данные и "иду пить чай" (точнее "продолжаю смотреть телевизор" ) через какое то данные НЕ ЗАМЕТНО обработались ... процесс ждет следующей порции данных ... основной процесс показывает результат (если он есть) и через равное количество кадров готовит данные для следующего захода .

Все ! Даже без бонуса в виде частичного исполнения кода на другом ядре это как минимум снижает нагрузку на мои нервные клетки .... 8) :idea:

ЗЫ
Кстати, как я уже писал в программах для виднды потоки можно использовать не применяя класс TThread...
обращаясь к ядру системы через WinApi (viewtopic.php?p=125032#p125032)
Там есть свои подводные камни но местами код получается даже проще чем с TThread .
ЗЫ ЗЫ
А конкретно по " ProcessMessages в Thread" (извиняюсь, что сразу не вник в суть замечания ... дискуссия воспарила в неведомые дали и я вместе с ней ... :roll: :D )
У меня application.ProcessMessages; вызывается в основном коде (потоке) .
Любой вызов application.ProcessMessages; из MyThread.Execute; гарантированно мгновенно вызывает КРАХ программы, а иногда и крах системы с "экраном синей смерти" !

А еще более конкретно While SMT.ProcessRUN do ; без application.ProcessMessages; просто полностью ВЕШАЕТ всю программу .... И шут знает почему ... (возможно проделки "быстрой оптимизации" ) по идее поток должен спокойно себе идти дальше до ProcessRUN:=False ; несмотря на то, что происходит в основном коде (в другом потоке )
Alex2013
долгожитель
 
Сообщения: 2922
Зарегистрирован: 03.04.2013 11:59:44

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

Сообщение olegy123 » 03.10.2017 00:09:11

Alex2013 писал(а): application.ProcessMessages;

Если нежелательно чтобы процесс заставлял работать процик на 100%, либо его нужно приоритет
Код: Выделить всё
TThreadPriority = (tpIdle, tpLowest, tpLower, tpNormal, tpHigher, tpHighest,tpTimeCritical);
thread.Priority=tpIdle;

либо в местах где можно подождать желательно сделать Sleep(ms);

Добавлено спустя 3 минуты 32 секунды:
Alex2013 писал(а):Кстати, как я уже писал в программах для виднды потоки можно использовать не применяя класс TThread...
обращаясь к ядру системы через WinApi
На самом деле TThread использует ту же WinApi
Только он уже TObject и умеет Synchronize - что для окошечного приложения очень важно..

Добавлено спустя 5 минут 50 секунд:
Alex2013 писал(а):Там есть свои подводные камни но местами код получается даже проще чем с TThread .

ничем не проще, за исключением что не тянут лишние мьютексы и envents-ы, которые помогают синхронизировать с главным процеесом и правильно ожидать завершение TThread..
Иначе придется все это ручками прописывать..
Процесс не только нужно запусить но его нужно еще уметь останавливать.. и завершать. Иначе ошибки будут сыпаться потоком..

Добавлено спустя 16 минут 37 секунд:
Alex2013 писал(а):юбой вызов application.ProcessMessages; из MyThread.Execute; гарантированно мгновенно вызывает КРАХ программы, а иногда и крах системы с "экраном синей смерти" !
При запуске программы ядро выделяет поток.. Любая программа, даже консольная "хелло ворлд" - это есть изолированный поток..
В оконной программе тоже есть главный единственный поток. он находится в цикле и обрабатывает поступления Message.. Отсюда окошко программы реагирует на перетаскивания, изменения размеров. На кнопку закрытия все это идет через WinProc..
Когда вы в программе напишите
Код: Выделить всё
for i:=0 to 100000000 do
begin
  sleep(1);
end

и оно будет выполнятся долго. При этом окошко подвиснет.. потому что главный процесс занят этим циклом.
чтобы окошко как то реагировала на добавим принудительную оброботку WinProc на поступившие Message
Код: Выделить всё
for i:=0 to 100000000 do
begin
  sleep(1);
application.ProcessMessages;
end

окошко шевелится..

но когда application.ProcessMessages; вызывается другим процессом - равносильно когда разные диспечера запустили разные поезда в однокалейку.. в одна и та же переменная может иметь разные значения в одно время..
Все это называется конкуренция за ресурс разными процессами..
olegy123
долгожитель
 
Сообщения: 1643
Зарегистрирован: 25.02.2016 12:10:20

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

Сообщение Alex2013 » 03.10.2017 00:52:04

olegy123 писал(а):
Alex2013 писал(а): application.ProcessMessages;

Если нежелательно чтобы процесс заставлял работать процик на 100%, либо его нужно приоритет
Код: Выделить всё
TThreadPriority = (tpIdle, tpLowest, tpLower, tpNormal, tpHigher, tpHighest,tpTimeCritical);
thread.Priority=tpIdle;

либо в местах где можно подождать желательно сделать Sleep(ms);

Ты не понял... вся эта бодяга из за того, что я ожидаю конца процесса распознавания после команды на прекращение поиска метки . Для чего ? Чтобы сосновой код не "сделал свое черное дело" изменив параметры там где они уже загружены в поток на "не извлечение " Чтобы такого не происходило вовремя штатной работы потока я просто блокирую часть настроек(типа изменения разрешения кадра ). Да по идее можно блокировать и разблокировать из самого потока... НО как показывает небольшая "коллекция минидампов" после "синдрома синей смерти системы" (я их годами уже не видел ! А тут "слет шинигами " прямо какой-то ! ) лучше из потока в настройки элементов интерфейса без крайне нужды не лезть ... Даже с Synchronize(); не всегда все проходит штатно ! :idea:
Процесс не только нужно запусить но его нужно еще уметь останавливать.. и завершать. Иначе ошибки будут сыпаться потоком..


Дык ! О чем и тема ...
Последний раз редактировалось Alex2013 03.10.2017 00:57:10, всего редактировалось 2 раз(а).
Alex2013
долгожитель
 
Сообщения: 2922
Зарегистрирован: 03.04.2013 11:59:44

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

Сообщение olegy123 » 03.10.2017 00:55:45

Alex2013 писал(а):Ты не понял... вся эта бодяга из за того, что я ожидаю конца процесса распознавания после команды на прекращение поиска метки .
никто не мешает мешает в основной цикл поиска вставить флаг прекращения работы.. даже тот же Terminated.
если Terminated=true то значит хватит работать..

Добавлено спустя 2 минуты 25 секунд:
Alex2013 писал(а):Чтобы сосновой код не "сделал свое черное дело" изменив параметры там где они уже загружены в поток на "не извлечение "

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

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

Сообщение Alex2013 » 03.10.2017 01:01:08

Ага и как потом "Воскрешать" скоропостижно "терминированный" поток не подскажешь? Бо как я не пытался не получается ! :idea:
дублируй параметры в трейде. Тогда сможешь запускать одновременно с разными параметрами..

"Ага" номер два ... :idea: Ну вообще-то я так и делаю для основных параметров но копировать ВСЕ запаришься .
Последний раз редактировалось Alex2013 03.10.2017 01:07:28, всего редактировалось 1 раз.
Alex2013
долгожитель
 
Сообщения: 2922
Зарегистрирован: 03.04.2013 11:59:44

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

Сообщение olegy123 » 03.10.2017 01:05:09

Alex2013 писал(а): НО как показывает небольшая "коллекция минидампов" после "синдрома синей смерти системы" (я их годами уже не видел ! А тут "слет шинигами " прямо какой-то ! )

А почему в программировании мало используют многопоточность? Потому что оно сложное. И не из-за того что требует особых знаний.. там знаний на одну главу учебника.
А то что требуется знать задачу во всех частях. Не все задачи могут паралелится и не все задачи выгодна многопоточность.

Как пример растовая обработка в CUDA/OpenCL - либл полноценных я еще не видел.

Добавлено спустя 5 минут 44 секунды:
Alex2013 писал(а):Ага и как потом "Воскрешать" скоропостижно "терминированный" поток не подскажешь? Бо как я не пытался не получается !
Так я ответил ранее..
Представь что тебе нужно посмотреть с середины фильм.. который смотрел неделю назад..
Вот есть файл -фильм и есть проигрыватель.. Запускаешь проигрыватель, загружаешь файл и.. переводишь на ту временную метку с которой хочешь посмотреть..
есть другой путь - изобрести машину времени и переместится на то время перед нажатием кнопки "стоп" и продолжить смотреть дальше..

Добавлено спустя 4 минуты 4 секунды:
Alex2013 писал(а):"Ага" номер два ... :idea: Ну вообще-то я так и делаю для основных параметров но копировать ВСЕ запаришься .
разве, у программеров жизнь легка?
Последний раз редактировалось olegy123 03.10.2017 01:17:23, всего редактировалось 1 раз.
olegy123
долгожитель
 
Сообщения: 1643
Зарегистрирован: 25.02.2016 12:10:20

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

Сообщение Alex2013 » 03.10.2017 01:16:19

Alex2013
долгожитель
 
Сообщения: 2922
Зарегистрирован: 03.04.2013 11:59:44

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

Сообщение olegy123 » 03.10.2017 01:21:37

Запускал CUDA/OpenCL
CUDA побогаче будет, NVIDIA хорошо продвигает.
olegy123
долгожитель
 
Сообщения: 1643
Зарегистрирован: 25.02.2016 12:10:20

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

Сообщение Alex2013 » 03.10.2017 01:37:30

NVIDIA для меня не вариант бо более 6-лет сижу основном на НЕ-ИГРОВЫХ-ноутбуках ...
(Да и до этого в был сторонником AMD+ATI ... что неудивительно после того как единственный раз за всю жизнь наблюдал РЕАЛЬНО ГОРЯЩУЮ видеокарту ... нет ты понял ОГНЕМ горящую ! Ага ! Прямо в системном блоке... Чудо пиротехники назвалось "Вантус" то бишь урезанная TNT2 от NVIDIA ... )
Alex2013
долгожитель
 
Сообщения: 2922
Зарегистрирован: 03.04.2013 11:59:44

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

Сообщение wadman » 03.10.2017 09:57:43

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

Всё плохо в приведенном коде.
Начиная от "ожидания" ответа потока и заканчивая processmessages.
Для таких случаев есть сообщения. Поток умеет их получать и умеет их отправлять.
Остается научиться работать с этим.

Посмотри мой компонент для работы с доп. потоками.
viewtopic.php?f=10&t=11509
Там это всё решено.

Добавлено спустя 2 минуты 36 секунд:
Alex2013 писал(а):"Ага" номер два ... Ну вообще-то я так и делаю для основных параметров но копировать ВСЕ запаришься .

В этом нет необходимости. Поток может засыпать в ожидании события (сообщения). Вот и пусть спит, пока ему делать нечего.
wadman
постоялец
 
Сообщения: 122
Зарегистрирован: 18.10.2016 15:54:28

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

Сообщение serbod » 03.10.2017 11:46:43

Alex2013Это очень-очень грубый способ ожидания сигнала от фонового потока. С тем же успехом можно обойтись без фонового потока и в каждом цикле делать Applictation.ProcessMessages(), чтобы интерфейс пользователя не зависал.

Основной поток приложения управляется сообщениями (сигналами). Ты кликнул мышкой - система послала сообщение с кодом WM_CLICK и координатами клика. И каждая программа имеет цикл обработчика сообщений, где вызывает соответствующую коду сообщения процедуру или передает сообщение дальше, обработчикам в подчиненных объектах. И было бы правильнее послать сообщение из фонового потока, которое будет обработано в основном приложении. Смотри SendMessage(), PostMessage() и модификатор message для методов классов контролов.
Код: Выделить всё
const
  WM_SOME_MESSAGE           = LM_USER + 2004;
type
  TMyForm = class(TForm)
  private
    procedure HandleSomeMessage(var Msg: TLMessage); message WM_SOME_MESSAGE;
  end;

implementation

procedure TMyForm.HandleSomeMessage(var Msg: TLMessage);
begin
  if Msg.wparam = 1 then
    // проверяем параметр и что-то делаем
end;

procedure TMyThread.Execute();
begin
  PostMessage(MyForm.Handle, WM_SOME_MESSAGE, 1, 0);
end;


http://wiki.freepascal.org/Multithreade ... n_Tutorial
Аватара пользователя
serbod
постоялец
 
Сообщения: 449
Зарегистрирован: 16.09.2016 11:03:02
Откуда: Минск

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

Сообщение olegy123 » 03.10.2017 14:23:26

не понимаю зачем вам вызывать Applictation.ProcessMessages() принудительно..
Оставьте это главному потоку, он умеет с ним работать.
olegy123
долгожитель
 
Сообщения: 1643
Зарегистрирован: 25.02.2016 12:10:20

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

Сообщение Alex2013 » 04.10.2017 04:06:18

1 Мне тоже не нравится способ ожидания завершения через "тупой while" даже с ProcessMessages для профилактики дедлока..
2 Это по сути мой первый проект, где от использования TThread возможно будет реальная польза. (Не считая по сути чужого "цельно стянутого" кода взятого для основы моего веб-сервера, где к тому-же все связанное с потоком, достаточно прозрачно и примитивно )
3 Использование PostMessage разумеется хорошая идея (Можно будет прорисовку результата поиска вызвать )
Но тут ни в какие ворота не лезет мой изрядно кривой конвейер обработки кадров (Проект исследовательский, а не прикладной в многое добавлено "на попробовать шо оно такое " .... Как результат совершенно дикое для нормальной программы количество фильтров и настроек . ) Все это засунуто в перессовку паинт-бокса (для смены кадров вызываемую из таймера) через длинную череду if CheckBoxXXX.Checked then begin end; и/или разных флагов и условий ...
Так что события через Message вещь удобная но малость "не в тему" (Я даже нажатие на копку обрабатываю просто поднимая в обработчике флаг )
4 Кстати эта "замечательная" сточка находится тут
Код: Выделить всё
// Включить/выключить   распознавание метки  + Блок на FRR и Вращения и т.д
procedure TCO_Form.CheckBox25Change(Sender: TObject);
begin
if not  CheckBox25.Checked and  (SMT<>NIL) then
begin
CheckBox26.Checked:=False;
if not  SMT.Suspended then
   While SMT.ProcessRUN do application.ProcessMessages;
   SMT.Suspend; While not SMT.Suspended do;
//(Можно и без Suspend; но зачем оставлять бесконечно крутится даже одну проверку флага ?   )
end;
// пресечет списка вращения   
if CheckBox27.Checked then  NewRML;
// снять/поставить  блокировки настроек .
Button2.Enabled:= not CheckBox25.Checked;
Button5.Enabled:= not CheckBox25.Checked;

CheckBox28.Enabled:= not CheckBox25.Checked;
CheckBox27.Enabled:= not CheckBox25.Checked;
CheckBox8. Enabled := not CheckBox25.Checked;
Edit4.Enabled:=not CheckBox25.Checked;
Edit1.Enabled:=not CheckBox25.Checked;
Edit2.Enabled:=not CheckBox25.Checked;
end;

То есть при ВЫКЛЮЧЕНИИ флага нужно подождать со снятием блокировки с настроек .
(Ну и как тут событие обработать ? ВНУТРИ обработчика CheckBoxChange .... Ага ! :idea: )
Последний раз редактировалось Alex2013 04.10.2017 22:39:22, всего редактировалось 1 раз.
Alex2013
долгожитель
 
Сообщения: 2922
Зарегистрирован: 03.04.2013 11:59:44

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

Сообщение wadman » 04.10.2017 09:55:16

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

Внутри обработчика нужно запустить поток, а в обработчике, который ловит окончание работы потока - остальное.
wadman
постоялец
 
Сообщения: 122
Зарегистрирован: 18.10.2016 15:54:28

Пред.След.

Вернуться в Lazarus

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

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

Рейтинг@Mail.ru