Перейти к содержанию
  • Регистрация
  • 0
david_yusupov

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

Вопрос

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

Пример:

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 эмодзи.

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

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

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


  • Похожий контент

    • От Виталий Иванов
      Есть такая идея. 
      Загружаю в TListView много элементов (от 500 до 1000 может и более) ситуация вынуждает грузить именно столько . Так вот когда начинаю создавать их кастомно после создания приходится вызвать oItem.Adapter.ResetView(oItem) (Если этого не делать то не корректно рассчитывается высота и ещё пару багов )  что соответсвенно вызывает подвисание интерфейса на Windows все круто это не так в глаза бросается, а на Android печалька форма зависает от 10 до 30 секунд 
      Так вот сам вопрос можно ли как это сделать в отдельном потоке что бы пользователю показывать какой нибудь Waiter. Или может кто как по другому предложит реализовать ? 
      Смотрел в сторону динамической подгрузки итемов но хотелось бы что и его поиск работал . 
    • От gonzales
      Доброго времени суток!
      Решаю следующую задачу, в приложении динамически формируются разные объекты, наследники от одного класса. При формировании объектов заполняется динамический массив этих элементов. Далее я хочу в отдельном потоке для каждого из элементов массива получить его состояние, то есть делаю запрос к серверу. Все это повешено на таймер, каждую секунду должен отрабатываться запрос. Все более менее работает в Windows, а на Андроиде со временем приложение валится. Вот код таймера, для читаемости я удалил куски с различными вариантами E. RootElements - это массив TEssense от которого есть наследники. Функции GetBoardCurrentValue, GetBoardMaxValue - по сути запросы к серверу. 
      Подскажите, правильно ли я оформляю работу с потоками для работы на Андроиде?
      procedure TForm1.MasterTimerTimer(Sender: TObject); begin TTask.Run( procedure var l, d, a: byte; i,j:integer; E: TEssence; p: Pointer; VirtualNode: IXMLNode; VirtualElementNode: IXMLNode; id: byte; begin l := Length(Form1.RoomElements); for j := 0 to l - 1 do begin E := Form1.RoomElements[j]; // Реле if E is TRele then begin d := (E as TRele).Device_ID; a := (E as TRele).Device_Adress; if Form1.GetBoardCurrentValue(d, a) = true then begin TThread.Synchronize(nil, procedure begin (E as TRele).ReleSwitch.IsChecked := Form1.device[d].Board[a].CurrentValue.ToBoolean; end); end; // (E as TRele).ReleOnTimer(E) end // Диммер else if E is TDimmer then begin d := (E as TDimmer).Device_ID; a := (E as TDimmer).Device_Adress; if Form1.GetBoardMaxValue(d, a) = true then begin TThread.Synchronize(nil, procedure begin if (Form1.device[d].Board[a].Type_ID = TType.Светодиод) or (Form1.device[d].Board[a].Type_ID = TType.Диммер220) then begin (E as TDimmer).DimmerValue.Text := (Form1.device[d].Board[a].MaxValue).ToString; end; end); end; // (E as TDimmer).DimmerOnTimer(E) end // Таймер else if E is TSTimer then begin id := (E as TSTimer).STimerIndex; Form1.FillHTTPRequest(0, 0, HTTP_GET_TIMER_INFO, id); if Form1.AnswerIsComming = HTTP_GET_TIMER_INFO then begin TThread.Synchronize(nil, procedure begin if Form1.HTTPAnswer.Data1 = 0 then (E as TSTimer).Interval.Text := 'OFF' else (E as TSTimer).Interval.Text := 'ON' end); end; // (E as TSTimer).STimerOnTimer(E); end; end; end); end;   
    • От Alex Bakulin
      Есть простая вроде бы задачка - в фоне загружать картинки для ListView. Делаю это так:
      procedure TImageThread.Execute; var i: integer; begin for i := 0 to FListView.Items.Count -1 do begin FimageIndex := i; Synchronize(LoadImage); end; end; Ожидается, что с ListView в это время будет относительно комфортно работать, и в фоне в ImageList будут подгружаться картинки и появляться в ListView. А на деле получается так, что все приложение виснет аццки на время загрузки картинок и не отвечает. И это как под Windows так и под Android.
    • От Mazzay
      Всем добрый день!
      Приоритет нитки для Windows имеет тип TThreadPriority:
      enum DECLSPEC_DENUM TThreadPriority : unsigned char { tpIdle, tpLowest, tpLower, tpNormal, tpHigher, tpHighest, tpTimeCritical }; __property TThreadPriority Priority = {read=GetPriority, write=SetPriority, nodefault}; Тут по названиям элементов множества всё предельно понятно.
       
      Для Android тип уже int:
      __property int Priority = {read=GetPriority, write=SetPriority, nodefault}; Нигде не могу найти возможные варианты значений для приоритета. Кто-нибудь знает?
       
    • От notricky
      На Android код, который работает исправно на Win  вызывает ошибку "CalledFromWrongThreadException: Only the original thread that created a view hierarcy can touch its views" 
      Смысл таков, что я пытаюсь показать форму из треда, у которой BorderStyle=none (роли это не играет).
      Решение в Андроиде заключается в том, чтобы пускать через  runOnUiThread  (то есть выполнять интерфейсные штуки в главном потоке). Как я понимаю, в firemonkey эту фичу должен выполнять Synchronize().
      Тем не менее, ошибка возникает.
      А при запуске в режиме дебага на андроид девайсе событие кнопки вообще не срабатывает иногда. А если срабатывает, то возникает описанное выше исключение.
      Я собрал тестовый пример и в нем не сразу видна ошибка, тогда как получил я ее на рабочем проекте.
      Цель: показать бизибокс на время бекграундных действий. Этот бизибокс у меня сначала был просто на каждой форме и я интерфейсно его вызывал, но теперь решил сделать отедльной формой (как и тоаст), но почему так происходит я не понял. Вы что скажете?
       
      unit Unit1; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Controls.Presentation, FMX.StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; TWorkThread = class(TThread) public procedure Execute; override; end; var Form1: TForm1; implementation {$R *.fmx} uses unit2; procedure TForm1.Button1Click(Sender: TObject); var t: TWorkThread; begin t := TWorkThread.Create(True); t.FreeOnTerminate := true; t.Start; end; { TWorkThread } procedure TWorkThread.Execute; begin inherited; Self.Synchronize(procedure begin Form2.Show; Form2.Top := Form1.Top; Form2.Left := Form1.Left; Form2.BringToFront; end); Terminate; end; end.  
    • От Камышев Александр
      Windows, FMX
      Возможно не совсем в тему форума, вопрос по архитектуре серверных служб, хотелось бы услышать мнения.
      Ситуация:
      IdHTTTPServer на каждый запрос создает поток, в этом потоке не обойтись без обращения к пулу данных в памяти. Пул - несколько наборов актуальных данных. Наборы данных асинхронно получаются из БД, имеют связи многие ко многим, один ко многим и периодически кэшируются в память в основном потоке. Т.к. обращение к пулу из потока - соответственно пул должен быть потокозащищенным. После обработки запроса, данные также отправляются в  основном потоке в очередь БД.
      1. Если весь пул закрыть в TCriticalSection - то на время использования его одним потоком все остальные будут ожидать. Обращение к очереди БД из потока получается также должно быть потокозащищенным. Не изящно.
      2. Можно задачу обработки положить в некую потокозащищенную очередь и остановить поток c помощью TSimpleEvent->WaitFor( INFINITE ). Далее в основном потоке работать с пулом данных и очередью БД без критических сессий и, после получения результата, запустить поток SetEvent(). Код будет проще и понятней, однако задачи будут выполняться синхронно, последовательно как и в первом случае.
      3. Можно закрывать TCriticalSection отдельные наборы данных, это возможно несколько увеличит быстродействие (не факт!), усложнит код и увеличит вероятность deadlock, т.к. для обработки одного запроса используется несколько наборов данных. Deadlock не будет, если перед обращением к следующему набору ( critical_section->Enter() ) копировать что необходимо из предыдущего и отпускать его ( critical_section->Leave() ) - тут становится важна стоимость операторов копирования.При больших объемах, стоимость копирования может перекрыть весь профит от частного обращения к наборам.
      TThread полезно использовать при длительных операциях ввода вывода и ресурсоемких операциях, т.е. когда нужно подождать, не останавливая основной поток. Выигрыша в производительности полагаю нет, к тому же переключения критических секций также имеют стоимость. 
      Вопросы:
      1. Какой вариант предпочтительней? Есть стандартные схемы?
      2. Как влияет количество ядер, процессоров, на быстродействие во втором и третьем случае?
    • От 97mik
      Как сделать так, чтобы во время выполнения долговременных операций у меня не "замораживался" интерфейс приложения? 
       
      Например, я выполняю по сети скачивания большого файла и на время скачивания отображаю индикатор загрузки. Но пока файл полностью не загрузиться индикатор не работает.
    • От Tarik02
      Я загружаю картинку в отдельном потоке из сервера(пока из localhost). Иногда бывает, картинка загружается, иногда - нет. Если закрыть программу, выскакивает ошибка:

    • От kidrock1
      Всем привет, друзья. Столкнулся со следующей проблемой. Создаётся поток с целью загрузки картинок во время чтения статьи. Да так чтобы основная форма в момент загрузки не была заморожена. Вот код:
      type ThreadHTTP1=class(TThread) private i:integer; public procedure Execute;override; procedure ShowResult1; end; procedure ThreadHTTP1.Execute; var j:integer; begin inherited; try lStream1 := TMemoryStream.Create; Form3.IdHTTP1.Get('http://totalmma.ru/newsupload/8306.jpg',lStream1); except // ShowMessage('no'); end; Synchronize(ShowResult1); end; procedure ThreadHTTP1.ShowResult1; begin ShowMessage(IntToStr(Form3.IDHTTP1.Response.ContentLength)); Form3.Image1.Bitmap.LoadFromStream(lStream1); Form3.Image1.Visible := true; Form3.Caption:=IntToStr(i)+' kbs'; Form3.IdHTTP1.Free; Stream.Free; end; procedure TForm3.Button1Click(Sender: TObject); var MyHTTP1:ThreadHTTP1; begin MyHTTP1 := ThreadHTTP1.Create(False); end; Так вот проблема в следующем. На винде всё работает. А вот когда компилируешь под андройд и переносишь на телефон, при нажатии на кнопке ничего не происходит. Очень прошу помочь, друзья.
    • От Kikoma
      Следующая ситуация:
       
      Есть база данных с полями: id, product_name, price, cart (корзина) - Думаю пояснять излишне.
       
      по условию cart>0 формируется запрос и заполняется TListBox кастомизированным Item-ом который содержит SpinBox. при изменении SpinBox вызывается процедура, которая вносит изменение в БД (cart) и высчитывает сумму в этом Item.
       
      Все работает, все хорошо, но...
      Задумал я что при SpinBox = 0, у меня этот TListBoxItem исчезал, для этого на изменение SpinBox если он равен 0, я запускаю процедуру формирования (Заполнения) этого TListBox заново.
       
      Вываливается ошибка Access ..to address XXX, при чем при пошаговой трассировки исключение вызывает FMX.Edit строка 3811 CustomEditBox.Change; в procedure TValueRangeCustomEditBox.DoAfterChange; (DELPHI XE6)
       
      т.е. моя процедура полностью отрабатывается (Заполняется новый список Item-ов) и возникает эта ошибка.
       
      При чем на 32-bit Windows все работает нормально, только на андроиде возникает это исключение, при чем приложение продолжает нормально функционировать.
       
      Если я правильно понимаю, то эта процедура DoAfterChange пытается что то сделать с объектом, которого уже нет.
       
      Это баг или я неправильно алгоритм построил?
       
       
  • Последние посетители   0 пользователей онлайн

    Ни одного зарегистрированного пользователя не просматривает данную страницу

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