Гость
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Как правильно убивать thread / 25 сообщений из 52, страница 1 из 3
19.01.2022, 14:56
    #40127804
svd
svd
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как правильно убивать thread
Всем привет.

Нить используется для фильтрации. Имеет свойство FreeOnTerminated = true. Нигде не останавливается и через Synchronyze добавляет элементы в Листбокс. Сама выборка из базы имеет ограниченное количество записей: когда пользователь хочет проскролировать ниже, стартует новая нить с новым запросом.

Проблема в следующая. Когда пользователь задает фильтр, то формируется новый запрос, проверяет, что что нить еще работает, то убивает ее:

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
class function TFetchThread.StartThreadFetch(const aSQL: String;
  const aAction: TFetchThreadAction; var aRef: TFetchThread; const aSortDesc: Boolean;
  aDSNotify: TDataSetNotifyEvent
  ): TFetchThread;
const
  C_FETCHTHREAD_MAX_COUNT_ON_TERMINATE = 100;
var
  counter: Integer;
begin
  Result := aRef;
  if (aAction <> ftaNone) then
  begin
    counter := 0;
    while Assigned(aRef) do
    begin
      if Application.Terminated then Exit;;

      if (aAction = ftaTerminate) then
        threadTerminate( aRef );
      Sleep(10);
      Application.ProcessMessages;
      if counter > C_FETCHTHREAD_MAX_COUNT_ON_TERMINATE then Break;
    end;
  end;
  if not Assigned(aRef) then
    Result := TFetchThread.Create( aSQL, aDSNotify, aRef, aSortDesc);
end;

class function TFetchThread.threadTerminate(aRef: TFetchThread): Boolean;
begin
  Result := not isThreadRun(aRef);
  if not Result then
  begin
    aRef.FDSNotify := nil;
    TFetchThread(aRef).Terminate;
    //aRef.Suspend;
    TerminateThread(aRef.Handle, 0);
  end;

  if not Result then
  begin
    Sleep(1);
    TFetchThread(aRef).Terminate;
  end;
end;




Но умирает нить не сразу, а непонятно когда и при каких условиях. Особенно если пользователь быстро меняет фильтр. Есть какой либо путь быстро убивать?
...
Рейтинг: 0 / 0
19.01.2022, 14:59
    #40127807
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как правильно убивать thread
svdНо умирает нить не сразу, а непонятно когда и при каких условиях.

При документированных: когда проверяет флаг Terminated и выходит из метода Execute.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
19.01.2022, 15:16
    #40127816
YuRock
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как правильно убивать thread
svd,

1. Для FreeOnTerminate-потоков практически всегда невозможно корректно работать со ссылкой на объект потока без дополнительных костылей типа зануления ссылки в OnTerminate (или как там) потока.

2. Функцию TerminateThread можно использовать лишь в очень специфических случаях, я знаю таких два:
2.1. В потоке нет выделения памяти (в т.ч. - не используются переменные автоматических типов вроде String), нет создания и манипулирования любыми ресурсами;
2.2. Это происходит непосредственно перед завершением программы, чтобы закрыться хоть как-то, не дождавшись корректного завершения потока (там запрос долгий завис, например). Т.е. когда уже пофиг на память и ресурсы - при закрытии процесса всё почистится.
Как видишь, это не твои случаи.

Корректно остановить (убить) поток можно лишь сделав его логику такой, чтобы он реагировал на какое-то событие, при убиении взводил его и проверял при этом переменную Terminated.
...
Рейтинг: 0 / 0
19.01.2022, 15:37
    #40127828
Belotsky Serge
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как правильно убивать thread
svd,

что мешает завести публичное поле задания (или метод для установки задания) в классе потока, и проверять наличие нового задания в Thread.Execute? Если есть задание, выполнить его, нет - поспать немножко?
И не нужно с каждым новым запросом освобождать и запускать поток. Когда нужно убить поток, со стороны главного просто установить Terminate или через задание для завершения.
...
Рейтинг: 0 / 0
19.01.2022, 16:10
    #40127845
svd
svd
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как правильно убивать thread
Спасибо за подсказки.

1. Убиваю нить, потому как если эта форма долгое время не активна (а это может быть полдня), то и данные на ней не нужны, а тем более thread.

2. Попробую вариант без FreeOnTerminate. Возможно ли заставить трэд убится в методе execute, когда цикл полностью пробежал?
...
Рейтинг: 0 / 0
19.01.2022, 16:14
    #40127846
alekcvp
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как правильно убивать thread
svd
2. Попробую вариант без FreeOnTerminate. Возможно ли заставить трэд убится в методе execute, когда цикл полностью пробежал?

Выйти из цикла и, соответственно, из метода Execute?..
...
Рейтинг: 0 / 0
19.01.2022, 16:19
    #40127851
ъъъъъ
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как правильно убивать thread
svd,

нить должна завершаться сама. Об этом в MSDN написано, много. Никаких TerminateTheread(), никогда.
Например, фукция нити в рабочем цикле периодически проверяет условие завершения (флажок, сообщение). Без вариантов.
TerminateTheread() зовут лишь в очень простых случаях (выше описали), либо совсем в крайних случаях, когда остаётся лишь слить воду, сохраняя лицо.
...
Рейтинг: 0 / 0
19.01.2022, 16:42
    #40127856
Fr0sT-Brutal
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как правильно убивать thread
Да действительно, пусть поток будет всегда. Одно поле с фильтром, одно поле (или метод) с event-ом просыпания. Главный поток установил фильтр через крит. секцию, взвел event, всё. Поток запроса шуршит с текущим фильтром, как только закончил - сбрасывает event и засыпает до его взведения. В цикле получения еще завести флаг, который бы проверял изменение фильтра и в этом случае начинал цикл заново с новым значением
...
Рейтинг: 0 / 0
19.01.2022, 16:44
    #40127857
Belotsky Serge
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как правильно убивать thread
svd
Спасибо за подсказки.

1. Убиваю нить, потому как если эта форма долгое время не активна (а это может быть полдня), то и данные на ней не нужны, а тем более thread.

2. Попробую вариант без FreeOnTerminate. Возможно ли заставить трэд убится в методе execute, когда цикл полностью пробежал?

1. Спящий поток много ресурсов не потребляет. Проверяйте есть ли задание, если нет, то спать! :)
2. В Execute вы поток не убьете, можно убить в OnTerminate.

Я вообще не понял, зачем для вашей задачи поток. Если юзер нажал кнопку, то выполните задание. Если нужно периодически обновлять инфу в ListBox, делайте это по таймеру.
...
Рейтинг: 0 / 0
19.01.2022, 17:59
    #40127879
svd
svd
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как правильно убивать thread
FreeOnTerminate = false и попробовал убивать и по событию onTerminated. Все идет хорошо, но как и прежде входит в Destroy, выполняет весь код, вконце прыгает в inherited и ждет до безобразия долго на вызове WaitFor (нормального завершения не дождался).
...
Рейтинг: 0 / 0
19.01.2022, 18:10
    #40127881
Fr0sT-Brutal
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как правильно убивать thread
svd
FreeOnTerminate = false и попробовал убивать и по событию onTerminated. Все идет хорошо, но как и прежде входит в Destroy, выполняет весь код, вконце прыгает в inherited и ждет до безобразия долго на вызове WaitFor (нормального завершения не дождался).

Потому что вытягивать себя за волосы из болота удавалось только известному барону, и то он не делал этого заряженным дробовиком, как пытаешься сделать ты
...
Рейтинг: 0 / 0
19.01.2022, 18:19
    #40127885
YuRock
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как правильно убивать thread
svd
Возможно ли заставить трэд убится в методе execute, когда цикл полностью пробежал?
Выход из - Execute - и есть окончание потока.
Перед созданием (пересозданием) просто удаляй его, и всё.
Код: pascal
1.
2.
ThreadObj.Free;
ThreadObj := TMyThread.Create;


И всё будет работать всегда, и в случае ThreadObj=nil, и Terminate будет само вызываться, когда надо.
...
Рейтинг: 0 / 0
19.01.2022, 18:23
    #40127886
YuRock
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как правильно убивать thread
svd
FreeOnTerminate = false и попробовал убивать и по событию onTerminated
В этом случае событие OnTerminate не нужно уже
svd
до безобразия долго на вызове WaitFor
Значит Execute крутится, не выходя по условию Terminated
...
Рейтинг: 0 / 0
19.01.2022, 18:23
    #40127887
ъъъъъ
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как правильно убивать thread
YuRock,

ТС не спрашивает, как должно быть, он спрашивает - что сделать, чтобы было так, как он хочет.
...
Рейтинг: 0 / 0
19.01.2022, 18:24
    #40127888
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как правильно убивать thread
svdпопробовал убивать и по событию onTerminated

Чудак, я сказал Terminated , а не onTerminate . Если ты считаешь
разницу в три буквы несущественной - прекрати пытаться программировать, это
бесперспективняк.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
19.01.2022, 18:28
    #40127891
ъъъъъ
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как правильно убивать thread
TThread - зло - (с).
...
Рейтинг: 0 / 0
19.01.2022, 18:52
    #40127906
Fr0sT-Brutal
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как правильно убивать thread
ъъъъъ
TThread - зло - (с).

Зло не TThread, а многочисленные его обвесы, которые предполагались для облегчения жизни чайникам, но на самом деле просто кладезь граблей.
...
Рейтинг: 0 / 0
19.01.2022, 19:04
    #40127911
ъъъъъ
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как правильно убивать thread
Fr0sT-Brutal,

я так и написал.

Если бы люди думали о нитях не как о волшебных объектах, а использовали CreateThread() из kernel32.dll, они бы хоть раз прочли https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createthread
...
Рейтинг: 0 / 0
19.01.2022, 19:24
    #40127915
rgreat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как правильно убивать thread
Смена одних объектов на другие не спасет от кривых рук.
...
Рейтинг: 0 / 0
19.01.2022, 19:43
    #40127920
Zelius
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как правильно убивать thread
svd,

Возможно это из-за Synchronize, который ждет пока его обработают в основном потоке, который ждет, пока доп. поток закончит работу. Возможно надо использовать RemoveQueuedEvents, или переделать отправку на PostMessage.
...
Рейтинг: 0 / 0
19.01.2022, 19:57
    #40127925
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как правильно убивать thread
ъъъъъЕсли бы люди думали о нитях не как о волшебных объектах, а использовали
CreateThread() из kernel32.dll, они бы хоть раз прочли

Главное чтобы они не пропустили при этом мимо ушей " никогда не используйте
CreateThread() в приложениях, использующих RTL
".
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
19.01.2022, 20:32
    #40127933
GunSmoker
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как правильно убивать thread
Ты до сих пор свой .Execute так и не показал - а это ведь самое важное в вопросе, а вовсе не как ты создаёшь или завершаешь поток.

В целом, задача решается так:
- При смене фильтра: если есть старый поток - делай ему .Terminate, но не жди его, сразу запускай новый
- Если надо остановить поток - делай ему .Terminate и забывай ссылку
- В самом потоке проверяй .Terminated в .Execute
- При выходе из потока - вызывай OnTerminate для того места, где у тебя ссылка на поток. Если ссылка = ты, то скидывай результаты на UI, если ссылка = не ты, то просто удаляй результаты. В конце удали себя

Таким образом, суть тут в том, что когда тебе надо "уничтожить поток", ты просто ставишь ему флажок и идёшь дальше. Сам поток увидит этот флажок после и завершится - тоже когда-то потом, тебе уже не важно когда. Т.е. в один момент времени у тебя может работать два (а иногда и более) потоков для фильтров: один из них - текущий, а остальные - в процессе завершения.
...
Рейтинг: 0 / 0
19.01.2022, 21:17
    #40127941
ъъъъъ
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как правильно убивать thread
GunSmoker
ты просто ставишь ему флажок и идёшь дальше. Сам поток увидит этот флажок после и завершится - тоже когда-то потом, тебе уже не важно когда.

А если ТС в треде использует объекты формы? Пишет, что листбокс заполняет. Форму убил - и нет листбокса.
...
Рейтинг: 0 / 0
19.01.2022, 21:48
    #40127946
GunSmoker
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как правильно убивать thread
Проблемы не увидел.
...
Рейтинг: 0 / 0
20.01.2022, 10:18
    #40128014
Fr0sT-Brutal
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Как правильно убивать thread
Да просто onTerminate вызывается через Synch, и ТС из него пытается прибить себя же, а деструктор через WaitFor бесконечно ждет окончания. Схема архитектурно кривая
...
Рейтинг: 0 / 0
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Как правильно убивать thread / 25 сообщений из 52, страница 1 из 3
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]