Перейти к содержанию
Fire Monkey от А до Я
  • 0

Убить поток TThread?


david_yusupov

Вопрос

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

Пример:

procedure TBufferThread.Execute;
begin
    while not Self.Terminated do
    begin
          Sleep(10000);
    end;
end;

 

Используя ReportMemoryLeaksOnShutdown показывает, что поток жив, после закрытие программы?

PS

Поток так же жив после вызова процедуры   TThread.Terminate (После того как заглянул вовнутрь понял почему, и поэтому возник вопрос, как убить поток?)

Ссылка на комментарий

Рекомендуемые сообщения

  • 2

Ответ - никак, нет такого механизма, в винде можно принудительно хэндл потока закрыть, но это тоже заканчивается крахом.

метод Terminate только выставляет флаг Terminated и все,

по флагу FreeOnTerminate, после отработки потока, т.е. после выхода из процедуры TBufferThread.Execute поток  будет удален автоматически.

Без необходимости не надо применять потоки, или применять потокозащищенные методы,

если уж никак, то работать с ними нужно трепетно: 

- не использовать засыпающие надолго функции типа Sleep(10000);

- в компонентах типа доступа к базам данных, tcp, http и т.п. жестко контролировать таймауты;

- не обращаться к компонентам основного потока, особенно к визуальным;

- для потоковой защиты использовать TInterlocked, TEvent или TSimpleEvent

- при большом объеме кода, расставлять проверки флага для выхода из цикла if ( Terminated ) break;

- дожидаться корректного окончания работы потока.

Изменено пользователем Камышев Александр
Ссылка на комментарий
  • 1

В случае виндовс, если очень хочется, можно создавать дочерние процессы,

в этих процессах что-то делать ресурсозатратное и уничтожать их в любое время.

Ссылка на комментарий
  • 1
5 минут назад, david_yusupov сказал:

Это все и так понятно... мда.

Ну а что вы хотели услышать?
Даже в Windows, где действительно можно явно "прибить" поток, это приведет к тому что самого потока не станет, но вся память, которую он забрал в ходе работы останется помеченной как "в использовании".

Несколько раз так создаем/прибиваем потоки и получаем OutOfMemory в любом случайном месте программного кода.

Поэтому убивать поток не надо, его надо корректно завершать.

Ссылка на комментарий
  • 1
10 минут назад, krapotkin сказал:

а что сложного в потоке предусмотреть выход, если поднят флаг Terminated ???

Если поток провалится в ожидание с параметром INFINITE или ReadUntilDisconnect, типа Socket.ReadStream то можно завеситься на неоределенное время и при поднятом флаге.

Ссылка на комментарий
  • 1

В наследнике TThread объявите  

FCancelledEvent: TSimpleEvent; 

Переопределите     TerminatedSet; 

в нем сделайте inherited и FCancelledEvent.SetEvent

Ну и вместо Sleep используйте FCancelledEvent.WaitFor

После этого Ваша проблема исчезнет
 

 

Ссылка на комментарий
  • 0

Посмотрите класс, реализующий альтернативный Sleep (под катом).

соль в следующем:

создаем потомка TThread, запускаем, ждем завершения:

class function TDelays.Delay(aDuration: integer): TDelay;
begin
  if not Assigned(FList) then
    FList := TList<TDelay>.Create;

  Result := TDelay.Create(aDuration);
  FList.Add(Result);
  Result.FreeOnTerminate := false;
  Result.OnTerminate     := OnTerminateItem;
  Result.Start;
  Result.WaitFor;
end;

Работаем с ним нежно

procedure TDelay.Execute;
begin
  inherited;

  while (not Terminated) and (MilliSecondsBetween(now, FStart) < FDelay) do
  begin
    sleep(100);
  end;
end;

По завершении работы убиваем:

class procedure TDelays.OnTerminateItem(Sender: TObject);
begin
  TTask.Run(
    procedure
    begin
      try
        if Assigned((Sender as TDelay)) then
        begin
          (Sender as TDelay).Free;
          FList.Remove((Sender as TDelay));
        end;
      except
      end;
    end);
end;

А можем убить и досрочно:

(TObject as TDelay).Free;

потому что в деструкторе стоит такой код:

destructor TDelay.Destroy;
begin
  Terminate;

  if (not Suspended) then
    WaitFor;

  inherited;
end;

 

uDelays.zip

Ссылка на комментарий

Присоединяйтесь к обсуждению

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

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...