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

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

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

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

Сообщение Alex2013 » 01.10.2017 12:26:12

Проблема скорее даже не в остановке, а в "Освобждении" по free ...
Дело в том, что у меня внутри TMyThread.Execute; создается множество временных объектов ...
И где именно "подвешивается" поток по команде Suspend заранее узнать нельзя ...
Если я остановив поток попытаюсь сделать MyThread.Free есть вероятность утечки памяти и прочих неприятностей .
А после MyThread.Terminate; поток почему-то не запускается снова ...
Так что один раз создав поток приходится оставлять его в памяти "на вечно".

Но не может же это быть ШТАТНЫМ методом работы с потоком ?

Посему назрели вопросы :
1 Как правильно останавливать( Suspend ) и завершать(Terminate) поток ?
( догадался, что местами нужно делать так MyThread.Suspend; While not MyThread.Suspended do; но как то это кривовато смотрится ... )
2 Можно ли полностью "освободить"(И как это делать правильно ...) экземпляр класса потока по free ?
Alex2013
энтузиаст
 
Сообщения: 710
Зарегистрирован: 03.04.2013 11:59:44

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

Сообщение Ichthyander » 01.10.2017 13:28:41

Внутри обработчика и циклов работы потока, проверяйте состояние свойства Terminated. Программно, самостоятельно. Если данный флаг установлен, то просто выходите из всех циклов и все. Потому что процедура Terminate просто выставляет значение свойства Terminated в True.
Suspend просто "замараживает" поток. И чтобы впоследствии освободить поток, надо его заново разморозить (Resume) и выставить Terminated в True с помощью Terminate (опять-таки не забывая соответствующие проверки в телепроцедуры Execute).
Если поток был создан с флагом FreeOnTerminate, то поток освободится самостоятельно. Если нет нужноего очистить самостоятельно с помощью процедуры Free
Аватара пользователя
Ichthyander
постоялец
 
Сообщения: 304
Зарегистрирован: 04.04.2007 08:32:43
Откуда: Астрахань

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

Сообщение olegy123 » 01.10.2017 14:07:38

Alex2013 писал(а):И где именно "подвешивается" поток по команде Suspend заранее узнать нельзя ...

Для этого используют синхронизации. Event, Mutex, Semaphore и др.

Считается что блокировать на уровне ядра процесс - это жеский хук.

проще рассчитать в каком месте нужно сделать остановку и что дальше надо делать..

Добавлено спустя 3 минуты 25 секунд:
Alex2013 писал(а):Если я остановив поток попытаюсь сделать MyThread.Free есть вероятность утечки памяти и прочих неприятностей .

Ядро выделяет процесс под код. Который главный поток вдург уничтожает все переменные.. Само ядро не вкурсе, продолжает выделять кванты времени, а там мусор.

Добавлено спустя 4 минуты 45 секунд:
Alex2013 писал(а):А после MyThread.Terminate; поток почему-то не запускается снова ...

Представь беговую дорожку - при Thread.Create - бегун подготовленный подходит к старту, встает на исходну.. Start() начинает бежать до финиша. А на финише нет Start().

Добавлено спустя 1 минуту 50 секунд:
Alex2013 писал(а):Так что один раз создав поток приходится оставлять его в памяти "на вечно".

со стороны ядра, любая программа это поток(нить).

Добавлено спустя 14 минут 23 секунды:
Alex2013 писал(а):1 Как правильно останавливать( Suspend ) и завершать(Terminate) поток ?

Зачем останавливать поток? Со сороны ядра поток не должен останавливаться.. это дополнительные издержки.
Сам поток должен знать когда ему остановится и где.

Alex2013 писал(а):2 Можно ли полностью "освободить"(И как это делать правильно ...) экземпляр класса потока по free ?

Ядру дают команду создать процесс в этой точке.. с таким то квантам времени и с такими правами..
Далее сам процесс выполнят задачи: решает, ивзлекает корни, рендерит картинки, пишет звук, занимается пилотированием устройст.. Решил что ему нужно остановится и ждать команды..
Для этого нужны всякие Event, Mutex, Semaphore - которые ядру говорят что пока бит не изменится дальше эта телега не поедет. А этот бит может изменить другой процесс..
Бит меняется - телега едет..
Задачу выполнил - есть финиш, ядру дают команду завершить нить.
И главная программа уже решает что делать с объектом-трейдом, может данные нужны для последующей обработки.. либо фри-шить объект.
olegy123
энтузиаст
 
Сообщения: 763
Зарегистрирован: 25.02.2016 12:10:20

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

Сообщение Ichthyander » 01.10.2017 15:05:50

Для простоты и наглядности работы в Lazarus c потоками кусок кода на уровне класса TThread
Код: Выделить всё

procedure TSomeThread.Execute;
begin
  ...
  не занимающие много процессорного времени процедуры
  ... занимающий много процессорного времени цикл
    while (некое условие) or not Terminated do
    begin
      ... ... ... 
    end;
  if Terminated then
    Здесь можно выполнить некие процедуры, которые необходимы при принудительном завершении потока
  else
    А здесь, как если бы поток завершил цикл без подсказки из основного потока.
end;

В теле основного потока, к примеру
Код: Выделить всё
ASomeThread.Terminate; // по сути эта команда не останавливает поток, а дает ему знать, что пора "закругляться", делать все необходимые процедуры по завершении и завершить процедуру Execute.

Ну это как пример, там свои ньюансы могут быть и должны в Вашем случае.
Если для потока установлен флаг FreeOnTerminate, то автоматически для потока запуститься процедура Destroy.
По сути Suspend Вам может понадобится, к примеру, для аварийной заморозки потока, но не для его закрытия.
Аватара пользователя
Ichthyander
постоялец
 
Сообщения: 304
Зарегистрирован: 04.04.2007 08:32:43
Откуда: Астрахань

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

Сообщение serbod » 01.10.2017 15:09:38

Посмотри исходник TThread, там не так много. И ты заметишь, что при Destroy() ставится признак Terminated, поток запускается (Suspended := False), и дожидается остановки WaitFor().

Из моего опыта постройки критичных к надежности систем:

Использовать TThread.FreeOnTerminate не желательно. Создание, инициализация и удаление объектов должно происходить внутри Execute(), в одном потоке, чтобы не было проблем с разными контекстами.

При инициализации и финализации DLL нельзя создавать или удалять фоновые процессы TThread!
Также внутри DLL нежелательно использовать Sleep(0), но можно Sleep(1) или больше.

При работе с динамически создаваемыми объектами следует придерживаться правила, что создание и удаление должно происходить в одном модуле, как можно ближе друг
к другу. В идеале так:

Код: Выделить всё
Obj := TObj.Create();
try
  Obj.Use();
finally
  Obj.Free();
end;
Аватара пользователя
serbod
постоялец
 
Сообщения: 215
Зарегистрирован: 16.09.2016 11:03:02
Откуда: Минск

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

Сообщение olegy123 » 01.10.2017 16:38:49

serbod писал(а):При инициализации и финализации DLL нельзя создавать или удалять фоновые процессы TThread!
Почему? Такие ограничение ни где не описаны.
serbod писал(а):При работе с динамически создаваемыми объектами следует придерживаться правила, что создание и удаление должно происходить в одном модуле, как можно ближе друг
к другу.
Что за ерунда..
serbod писал(а):Использовать TThread.FreeOnTerminate не желательно. Создание, инициализация и удаление объектов должно происходить внутри Execute(), в одном потоке, чтобы не было проблем с разными контекстами.
Вы вводите в заблуждение..

Добавлено спустя 4 минуты 28 секунд:
TThread это "ручка" для управления потоками.
olegy123
энтузиаст
 
Сообщения: 763
Зарегистрирован: 25.02.2016 12:10:20

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

Сообщение Alex2013 » 01.10.2017 19:10:00

"Для нашего брата дело рогато ..." :shock: :D
Но ладно "где наша не пропадала" !

Suspend мне нужен для того что бы процесс не продолжался тогда когда это не надо .
Например у меня принудительно блокируется часть настроек пока включена галка "Включить распознавание" ...
...все отлично работало пока поиск метки шел в общем потоке . Но теперь я выключаю галку а процесс еще идет ...

Я сделал так, что поток обрабатывает данные, а потом ЖДЕТ следующей порции данных .
Но фокус в том галку можно выключать в ЛЮБОЙ момент, хоть сразу после старта .

Раньше это приводило к тому на следующем кадре обработка просто проскакивала содействующую ветку кода .
А теперь если его не остановить поток работает "невзирая на лица" а поскольку БЛОКИРОВКА критических настроек снята
я могу что-то изменить в настройках после того как процесс в потоке запустил цикл по этим данным .

Даже просто слишком быстрый клик "вкл/выкл" может создать исключение если я умудрюсь сделать это черное дело достаточно быстро ... Так что прямо в обработчике изменения ЧескБкса стоит что-то вроде этой строчки if MyThread<>Nil then MyThread.Suspend; While not MyThread.Suspended do;
Alex2013
энтузиаст
 
Сообщения: 710
Зарегистрирован: 03.04.2013 11:59:44

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

Сообщение serbod » 01.10.2017 20:21:04

olegy123 писал(а):
serbod писал(а):При инициализации и финализации DLL нельзя создавать или удалять фоновые процессы TThread!
Почему? Такие ограничение ни где не описаны.


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

olegy123 писал(а):
serbod писал(а):При работе с динамически создаваемыми объектами следует придерживаться правила, что создание и удаление должно происходить в одном модуле, как можно ближе друг
к другу.
Что за ерунда..

Это золотое правило работы с динамически создаваемыми объектами. В Паскале нет сборщика мусора и автоподсчет ссылок тоже не везде и не всегда работает. Поэтому чтобы случайно не залететь, лучше предохраняться.

olegy123 писал(а):
serbod писал(а):Использовать TThread.FreeOnTerminate не желательно. Создание, инициализация и удаление объектов должно происходить внутри Execute(), в одном потоке, чтобы не было проблем с разными контекстами.
Вы вводите в заблуждение..

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

olegy123 писал(а):Добавлено спустя 4 минуты 28 секунд:
TThread это "ручка" для управления потоками.

Скорее, "обертка" над функционалом операционной системы. А handle это идентификатор контекста для имитации объектно-ориентированного программирования.
Аватара пользователя
serbod
постоялец
 
Сообщения: 215
Зарегистрирован: 16.09.2016 11:03:02
Откуда: Минск

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

Сообщение olegy123 » 01.10.2017 23:21:08

serbod писал(а):
olegy123 писал(а):
serbod писал(а):При работе с динамически создаваемыми объектами следует придерживаться правила, что создание и удаление должно происходить в одном модуле, как можно ближе друг
к другу.
Что за ерунда..

Это золотое правило работы с динамически создаваемыми объектами. В Паскале нет сборщика мусора и автоподсчет ссылок тоже не везде и не всегда работает. Поэтому чтобы случайно не залететь, лучше предохраняться.
Возможно имели ввиду не "динамически создаваемыми объектами", а атомарными..
Вообще ядру без разницы где сейчас работает нить, для него нужно вовремя переключать планировщик, строго выделять кванты времени на задачу. все остальное должен думать программист.

На счет сборщика мусора и автоподсчет ссылок - это для ленивых, которые не продумывают до конца жизнь объекта. А при мултипотоковости нужно знать что с данными происходить в любом месте.

Добавлено спустя 13 минут 57 секунд:
serbod писал(а):
olegy123 писал(а):
serbod писал(а):Использовать TThread.FreeOnTerminate не желательно. Создание, инициализация и удаление объектов должно происходить внутри Execute(), в одном потоке, чтобы не было проблем с разными контекстами.
Вы вводите в заблуждение..

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

Создание и удаление данных вообще происходит в куче, данные могут подгружаться извне: файл, сеть. Даже создаваться одним процессом и удалятся другими..
Не обязательно все создавать все в Execute(). Execute() - это тело процесса, в котором код будет выполнен отдельно от главного.
FreeOnTerminate - создан для тех кто не хочет фрешить трейд в ручную.

Добавлено спустя 26 минут 1 секунду:
Alex2013 писал(а): Suspend мне нужен для того что бы процесс не продолжался тогда когда это не надо .
Например у меня принудительно блокируется часть настроек пока включена галка "Включить распознавание" ...
...все отлично работало пока поиск метки шел в общем потоке . Но теперь я выключаю галку а процесс еще идет ...
У меня тоже в свое время было увлечение Suspend. Пока я не начал писать на Java. Там оного нет. Спросил гуру программиста как теперь жить?
На чту Гуру, после двух стаканов огненной воды принесенных в жертву ему согласился мне приоткрыть эту тайну.
Взял обычный волчек и раскрутил его, и пока он крутился сказал мне "Thread всегда должен работать". После волчек еще долго крутился, а потом остановился и упал...

Suspend - это атавизм, как копчик.. Его не стоит применять везде.
olegy123
энтузиаст
 
Сообщения: 763
Зарегистрирован: 25.02.2016 12:10:20

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

Сообщение serbod » 02.10.2017 02:07:33

olegy123 писал(а):Возможно имели ввиду не "динамически создаваемыми объектами", а атомарными..

Атомарные переменные - это совсем другое. Я имею в виду именно корректное создание и освобождение объектов внутри потока, отработку исключений. Сбой внутри потока может долгое время оставаться незамеченным и не поддаваться отладке. Аналогичный сбой в продакшене - это совсем беда, поскольку даже стандартного окна ошибки не будет, в лучшем случае сразу зависнет, а обычно через некоторое время, и уловить взаимосвязь очень сложно. Поэтому многопоточность нужно тщательно проверять отдельно, на максимальной нагрузке, с имитацией сбоев (деление на ноль, переход по нулевому адресу, итд..).

olegy123 писал(а):Создание и удаление данных вообще происходит в куче, данные могут подгружаться извне: файл, сеть. Даже создаваться одним процессом и удалятся другими..
Вот от этого я и пытаюсь предостеречь. Нельзя создавать объекты в одном месте, а освобождать в другом. Процессору-то пофиг, а вот операционной системе не пофиг, она отвечает за выделение и освобождение ресурсов. Даже если есть необходимость сделать раздельное выделение-освобождение, в операционной системе для этого есть специальные средства - CreateFileMapping(), DuplicateHandle(), буфер обмена и тому подобное, когда программа создает объект, передает другой программе, а потом "закрывает" объект, но он остается в памяти пока другая программа его не "закроет". С потоками в этом плане проще, но принцип проектирования тот же, нельзя оставлять объекты висеть в памяти неизвестно под чьим контролем. Либо делать привязку к владельцу и уничтожать вместе с владельцем, либо делать счетчик ссылок (через IInterface или type object).

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

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

Сообщение olegy123 » 02.10.2017 04:03:44

serbod писал(а):Атомарные переменные - это совсем другое. Я имею в виду именно корректное создание и освобождение объектов внутри потока, отработку исключений.
Чем различается создание объекта, работу данных, уничтожение объектов.. Те же ошибки.. Ничем.
Есть общий менеджер памяти, общая куча, общая файловая система..

serbod писал(а):Поэтому многопоточность нужно тщательно проверять отдельно, на максимальной нагрузке, с имитацией сбоев (деление на ноль, переход по нулевому адресу, итд..).

Многопоточность действительно требует тщательного подхода к реализации задачи, она сложна тем что требует контроля над процессом. Понимание что такое конкуренция, отчего нужны ожидания, синхронизация.. Не всегда задача может быть распараллелина, отсюда не стоит везде применять многопоточность.

serbod писал(а):Нельзя создавать объекты в одном месте, а освобождать в другом.
Это фобии.. я вообще даже не всегда применяю атомарность. В моде сейчас вообще избегания мьютексов на основе ядра, так как они затратны..
https://www.youtube.com/watch?v=yVZPJ4dCF9Q

serbod писал(а):Процессору-то пофиг, а вот операционной системе не пофиг, она отвечает за выделение и освобождение ресурсов.
сейчас уронить систему довольно сложно. Даже если процесс вылетел - система должна сбросить все выделенные ресурсы.
А вот на счет переполнения ресурсов - так это к многопоточному программированию не имеет никакого отношения..

Добавлено спустя 44 минуты 20 секунд:
serbod писал(а):С потоками в этом плане проще, но принцип проектирования тот же, нельзя оставлять объекты висеть в памяти неизвестно под чьим контролем. Либо делать привязку к владельцу и уничтожать вместе с владельцем, либо делать счетчик ссылок (через IInterface или type object).
В соседней ветке идет обсуждение о передаче через mail DBF файла.. Там владелец создает данные, передает.. Дальше данные живут своей жизьню, и не обязательно что они дойдут до адресата..
Контролировать всю передачу на этапе создания одним владельцем - невозможно. Таких задач на самом деле достаточно много даже внутри системы, даже процесса..
Один из примеров - автоматическая очистка мусора..

Добавлено спустя 5 часов 58 минут 46 секунд:
serbod писал(а):Даже если есть необходимость сделать раздельное выделение-освобождение, в операционной системе для этого есть специальные средства - CreateFileMapping(), DuplicateHandle(), буфер обмена и тому подобное, когда программа создает объект, передает другой программе, а потом "закрывает" объект, но он остается в памяти пока другая программа его не "закроет".

Все это делается просто - мьютекс + хендл: мьютекс лочится идет проверка хнедл закрыт, если нет идет работа, по окончании мьютекс открывается.. хоть 10^4 трейдов они сработают..
Вы думаете, что CreateFileMapping(), DuplicateHandle() волшебные функции, сделанные волшебниками? Я не понимаю зачем мне отображения в память.. что оно мне дает кроме как обмена между внутренними процессами? А с DuplicateHandle() - судя по описанию, должно быть простой подсчет ссылок.
К гениальным фокусам поверьте там не пахнет.

Добавлено спустя 5 минут 6 секунд:
serbod писал(а): Да, автоматическое закрытие проще и удобнее, но может возникнуть ситуация, когда дверь захлопнулась, а ключ забыли.

Если вы про запирание мьютексов - то во всех книжках этот случай расписан.
olegy123
энтузиаст
 
Сообщения: 763
Зарегистрирован: 25.02.2016 12:10:20

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

Сообщение serbod » 02.10.2017 11:42:29

olegy123 Все зависит от уровня безопасности и надежности программы. Для прототипов или экспериментов я тоже грешным делом не утруждаю себя соблюдением своих же правил - говорящие имена, удаление объектов, иерархичность взаимосвязей, try..finally, проверки параметров и отсутствие предупреждений компилятора при максимуме проверок. Собралась, запустилась, ну и норм. Но потом бывает страдаю от этого, когда беру куски кода из прототипа в рабочие проекты. У меня такие задачи, что программы работают в виде распределенной системы на тысячах машин, круглосуточно без выходных. И мне приходится учитывать проблемы, с которыми большинство никогда не сталкивается - переполнение 32-битного таймера GetTickCount() в течении 40 дней, фрагментация сегментов динамической памяти, некритичные сбои железа - сетевых карт и модемов, дисков, USB-устройств. То, что обычно решают перезапуском программы или компьютера. В моем случае перезапуск - это крайняя мера. Даже регламентные работы по обновлению софта согласуются в министерстве, а если систему не удается восстаноить больше часа, то это уже ЧП и серьезное внутреннее расследование с поиском крайних. Поэтому я намеренно избегаю любого риска и неопределенности.

Слышал, что аналогичные проблемы испытывали разработчики Майкрософт, которые сначала делали дешевую систему "одного рабочего дня" без гарантий, где любую проблему может решить перезапуском. Но когда винда массово стала ассоциироваться с глюками и продажи упали, им пришлось задуматься о надежности. Им пришлось выработать ограничения и правила, четко соблюдать их в ущерб производительности и удобству. Винда научилась привязывать выделяемые ресурсы (память, хендлы, дескрипторы GUI) к запросившему их приложению, а в некоторых случаях и потоку. А также проверять доступ к этим ресурсам, защищать от изменений другими приложениями. И при завершении потока или приложения освобождать эти ресурсы. В Win95 такого не было, любая программа могла потерять выделенные ресурсы, залезть в чужую область памяти или обратиться к открытому другими порту или устройству, и даже убить всю систему. В WinNT и далее с этим начали бороться и сейчас каждое приложение работает в своей виртуальной "песочнице", где многие устройства и функции эмулируются. В плане использования памяти, GUI и основных устройств ввода-вывода для программ все хорошо, винда дает программам возможность безболезненно совершать ошибки, лезть в освобожденную память и терять хендлы, за счет "бронирования" сегментов памяти за конкретной программой, даже если программа вернула память системе. При закрытии программы винда все подчистит и память станет неиспользуемой. Но если неиспользуемая память закончилась, то винда начинает повторно выделять память в "бронированных" участках, и если программа к ним повторно обратится, то получит сбой. С одной стороны, этот сбой может никогда и не случиться, если памяти хватает. А с другой стороны, если сбой случится, то будет очень трудно найти его причину. Насчет линукса не знаю, там вроде с этим построже и сбой будет при первом же некорректном использовании памяти.

Насчет привязки ресурсов к потокам внутри приложения подробностей не помню. Вроде у мьютексов оно есть, и это может привести к бесконечным блокировкам при неправильном использовании. А TThread в винде как раз использует мьютекс в качестве семафора для WaitFor, и если вызвать WaitFor не из основного потока (и даже контекста в случае с DLL), то будет deadlock.

Добавлено спустя 5 минут 52 секунды:
olegy123 писал(а):Если вы про запирание мьютексов - то во всех книжках этот случай расписан.

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

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

Сообщение olegy123 » 02.10.2017 12:42:47

serbod писал(а):olegy123 Все зависит от уровня безопасности и надежности программы. Для прототипов или экспериментов я тоже грешным делом не утруждаю себя соблюдением своих же правил - говорящие имена, удаление объектов, иерархичность взаимосвязей, try..finally, проверки параметров и отсутствие предупреждений компилятора при максимуме проверок. Собралась, запустилась, ну и норм. Но потом бывает страдаю от этого, когда беру куски кода из прототипа в рабочие проекты. У меня такие задачи, что программы работают в виде распределенной системы на тысячах машин, круглосуточно без выходных.
Вы там шо? Операционку переписываете или приделываете костыли?
В свое время, когда был очень молод, красив собой и много дури расцветало в голове.. занимался разной херней - вместо того чтобы в 1Ске v7.7 написать обработчик, делал анимированные барабаны.. хотел сделать многозадачность в 1Ске, типа когда идет обработка, бухи релаксировали над анимацией. Ходил хвастался к бухам, после чего дали мне пенделя.. почему то не оценили этот поступок..
В то же время я был очень увлечен безопасностью своего кода, стабильностью выполнения задачи.. и на простую функцию (z:=a/b;)мог написать десять проверок(считал что try except finally - придумали трусы).. деления на ноль, переполнения числа, а что делать с целой частью.. а что будет с дробной.. А что будет если проверка не сработает? И начинаю писать уже второй слой проверки.. проверку на проверку, которая проверять на нуль. Весело? В какой то момент я понял что это фобия и из него нужно бежать.

serbod писал(а):И мне приходится учитывать проблемы, с которыми большинство никогда не сталкивается - переполнение 32-битного таймера GetTickCount() в течении 40 дней, фрагментация сегментов динамической памяти, некритичные сбои железа - сетевых карт и модемов, дисков, USB-устройств. То, что обычно решают перезапуском программы или компьютера. В моем случае перезапуск - это крайняя мера. Даже регламентные работы по обновлению софта согласуются в министерстве, а если систему не удается восстаноить больше часа, то это уже ЧП и серьезное внутреннее расследование с поиском крайних. Поэтому я намеренно избегаю любого риска и неопределенности.
Чё то тут не понимаю, вы пишете операционку или подсчитываете тики? Может вы делаете драйвера для USB-устройств, сетевых карт и модемов? Может вы подпольно upgred для видокарт NVIDIA или AMD..
Слышал об одних хопцев которые сделали станок по восстановлению блинов на HDD, но когда они сделали подлые америкосы с хитрыми азиатами выпустили блины с большей плотностью и по цене меньше чем стоимость восстановления. Возможно все..
По поводу мнистерства - ответ такой они напридумывали ставить данную систему, хай несут ответственность.

Добавлено спустя 12 минут 48 секунд:
serbod писал(а):Слышал, что аналогичные проблемы испытывали разработчики Майкрософт, которые сначала делали дешевую систему "одного рабочего дня" без гарантий, где любую проблему может решить перезапуском. Но когда винда массово стала ассоциироваться с глюками и продажи упали, им пришлось задуматься о надежности. Им пришлось выработать ограничения и правила, четко соблюдать их в ущерб производительности и удобству. Винда научилась привязывать выделяемые ресурсы (память, хендлы, дескрипторы GUI) к запросившему их приложению, а в некоторых случаях и потоку. А также проверять доступ к этим ресурсам, защищать от изменений другими приложениями. И при завершении потока или приложения освобождать эти ресурсы. В Win95 такого не было, любая программа могла потерять выделенные ресурсы, залезть в чужую область памяти или обратиться к открытому другими порту или устройству, и даже убить всю систему. В WinNT и далее с этим начали бороться и сейчас каждое приложение работает в своей виртуальной "песочнице", где многие устройства и функции эмулируются. В плане использования памяти, GUI и основных устройств ввода-вывода для программ все хорошо, винда дает программам возможность безболезненно совершать ошибки, лезть в освобожденную память и терять хендлы, за счет "бронирования" сегментов памяти за конкретной программой, даже если программа вернула память системе. При закрытии программы винда все подчистит и память станет неиспользуемой. Но если неиспользуемая память закончилась, то винда начинает повторно выделять память в "бронированных" участках, и если программа к ним повторно обратится, то получит сбой. С одной стороны, этот сбой может никогда и не случиться, если памяти хватает. А с другой стороны, если сбой случится, то будет очень трудно найти его причину. Насчет линукса не знаю, там вроде с этим построже и сбой будет при первом же некорректном использовании памяти.
видимо сами патчите винду раз такие глубокие познания..
По поводу "неиспользуемая память закончилась" - что такое может быть что так быстро память закончилась? Неужели вам 640кб ОЗУ вначале хватает? Что может размещаться в памяти?
У меня стоит вопрос по поводу обмена данными, использования stream между процессами. Там выгодно использовать memory map - но я понимаю что мне не нужно размещать 999Tb в 4Гб памяти, нужно стримить порциями.. фрагмент не будет привышать 128кб - то выделить в памяти 128кб вполне достаточно.. далее как в tutoral loop-ишь..
Linux использует принципы POSIX, винда типа тоже - у них 70% одинаковый подход.. поэтому перенос возможен и не так категорично сложен.

Добавлено спустя 15 минут 16 секунд:
serbod писал(а):Насчет привязки ресурсов к потокам внутри приложения подробностей не помню. Вроде у мьютексов оно есть, и это может привести к бесконечным блокировкам при неправильном использовании. А TThread в винде как раз использует мьютекс в качестве семафора для WaitFor, и если вызвать WaitFor не из основного потока (и даже контекста в случае с DLL), то будет deadlock.
Нет, мьютекс это к ядру, есть таблица(как я понимаю) где ядро видит какие нити обратились(залочили) и соответственно не должны работать, пока кто то не освободит(unlock).
Работу мютексов(точнее семафоров) любят описывать на примере к доступу к файлу нескольких процессов.. действительно файловая система базируется на этих механизмов.

serbod писал(а):
olegy123 писал(а):Если вы про запирание мьютексов - то во всех книжках этот случай расписан.

Значит, кто-то уже наступал на эти грабли, раз в книжках пишут. И вы тоже будет писать, если потратите месяцы и годы на поиск и устранение беды, которую можно было предотвратить за пять минут, не поленившись следовать простым правилам.
Когда вам нужно за пару дней написать рабочий стабильный код, тут брать череп(мьтютекс) бедного Йорика и рассуждать "быть или не быть, вот в чем вопрос" нет времени..
Подкачал шины у велосипеда, натянул цепь - и поехал..
Если бы было так сложно то мультипроцессорность преподавалось бы в очень специализированных учебниках, которые могли бы понять и пременять только люди с тремя ВО, имеющий опыт лет так за 10..
Но на самом деле - есть TThread и есть Exception - это все что нужно по минимуму для старта в этот мир.
olegy123
энтузиаст
 
Сообщения: 763
Зарегистрирован: 25.02.2016 12:10:20

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

Сообщение serbod » 02.10.2017 13:19:01

olegy123 писал(а):Вы там шо? Операционку переписываете или приделываете костыли?

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

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

Сообщение Alex2013 » 02.10.2017 19:50:14

Рад что тема оказалось интересной не только мне ..
За подсказки спасибо ! Кое что уже проверил на практике .
Обнаружил что чтобы программа не повисала при ожидании флага из потока нужно "отдавать тики в ручную"

Как-то так :
if (SMT<>NIL) then
While SMT.ProcessRUN do application.ProcessMessages;

SMT - мой поток .
SMT.ProcessRUN - флаг процесса (описывать долго проще заглянуть в код ).
Код: Выделить всё
procedure TSMThread.Execute;
while (not Terminated) do begin
IF  UPDATE  Then
begin
UPDATE:=False;  ProcessRUN :=True;

... // Поиск метки

ProcessRUN :=False;
  end
end
end;

Хотя например ожидание остановки работает и так .
SMT.Suspend; While not SMT.Suspended do;
Интересно почему ? (Догадки есть, но не очень внятные... и "смутные сомнения" мучат : вдруг я вообще чего-то элементного не учитываю ? )
Alex2013
энтузиаст
 
Сообщения: 710
Зарегистрирован: 03.04.2013 11:59:44

След.

Вернуться в Lazarus

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

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

Рейтинг@Mail.ru