Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2006.12.17;
Скачать: CL | DM;

Вниз

Как правильно закрыть все потоки закрывая программу?   Найти похожие ветки 

 
Gear   (2006-11-03 10:38) [0]

Из главного потока создаю несколько, которые занимаются закачкой из сети.
Нужно чтобы при закрытии основной программы, сначала закончились все потоки, и только затем завершался главный поток программы.
Делаю так:
1) В потоках делаю что-то типа
While not Terminated do begin
end;
2) Держу ThreadList и имею функцию что-то типа:

procedure TForm1.Term;
var
 i:integer;
begin
  with ThreadList, LockList do
   try
      for i := 0 to Count - 1 do
      begin
         TThr(Items[i]).Terminate;
      end;
   finally
     UnlockList
   end;
end;

Такую функцию вешаю на кнопку и жду завершения потоков. Но что-то всё это не работает.
Подскажие пож-та как решить правильно мою задачу?


 
Сергей М. ©   (2006-11-03 10:41) [1]


> что-то всё это не работает.


Что значит "не работает" ?


 
Gear   (2006-11-03 11:01) [2]

Если повесить на кнопку процедуру Term то всё работает. Но как сделать это при закрытии программы? Как узнать убились ли все потоки, а потом только разрешить закрыться программе?


 
Ketmar ©   (2006-11-03 11:02) [3]

у-у-у... повесь лучше какого-нибудь негра. процедуру-то за что вешать?


 
Сергей М. ©   (2006-11-03 11:08) [4]


> как сделать это при закрытии программы?


Например, используя ExitProcessProc


> Как узнать убились ли все потоки


Это зависит от того как ты реализовал свой TThr


 
Gear   (2006-11-03 11:11) [5]

Есть пример как надо? И в какую сторону копать?


 
Сергей М. ©   (2006-11-03 11:12) [6]

А с какой целью ты используешь TThreadList ?


 
Gear   (2006-11-03 11:14) [7]

Только чтобы их прибить. Других способов я незнаю.


 
Сергей М. ©   (2006-11-03 11:17) [8]

Ну а почему, скажем, не TList и не TObjectList ?
Ведь какими-то соображениями ты, наверно, руководствовался, выбирая именно этот класс для управления списком ? Или от балды выбрал его ?)


 
Gear   (2006-11-03 11:24) [9]

От балды, увидел пример и всё.


 
Сергей М. ©   (2006-11-03 11:26) [10]

Ну плохо что от балды)

Какое макс.число потоков может существовать у тебя ?


 
Gear   (2006-11-03 11:29) [11]

не более 5-10


 
Сергей М. ©   (2006-11-03 11:30) [12]

Чему равно св-во FreeOnTerminate ?


 
Gear   (2006-11-03 11:34) [13]

constructor TThr.Create(uri:TStringList);
begin
inherited Create(True);
Form1.ThreadList.Add(Self);
Furi:=Tstringlist.Create;
Furi.AddStrings(rssuri);
FreeOnTerminate:=True;
resume;
end;


 
Сергей М. ©   (2006-11-03 11:48) [14]

constructor TThr.Create(uri:TStringList);
begin
inherited Create(True);
...
Form1.ThreadList.Add(Self);
...
end;

destructor TThr.Destroy; //override !
begin
..
 inherited;
 Form1.ThreadList.Remove(Self);
..  
end;

...

with ThreadList.LockList do
  try
     for i := 0 to Count - 1 do
        TThr(Items[i]).Terminate;
  finally
    UnlockList
  end;

while True do
  with ThreadList.LockList do
  try
     if Count = 0 then Break;
  finally
    UnlockList
  end;


 
Gear   (2006-11-03 12:07) [15]

вот до этого места

while True do
 with ThreadList.LockList do
 try
    if Count = 0 then Break;
 finally
   UnlockList
 end;

у меня всё так.

Куда вот это?


 
Сергей М. ©   (2006-11-03 12:33) [16]

Вот именно туда куда я написал, т.е. непосредственно следом за

with ThreadList.LockList do
 try
    for i := 0 to Count - 1 do
       TThr(Items[i]).Terminate;
 finally
   UnlockList
 end;


 
Gear   (2006-11-03 12:59) [17]

хорошо, а это всё вешать на OnClose?


 
Gear   (2006-11-03 13:03) [18]

Программа виснет. Видимо в цикле
while True do
with ThreadList.LockList do
try
   if Count = 0 then Break;
finally
  UnlockList
end;

sleep(1000) не помогает


 
Дмитрий Белькевич ©   (2006-11-03 13:18) [19]

>Программа виснет. Видимо в цикле

Так посмотри, там или нет - бряк не долго поставить.
Если там, то собсно у тебя Terminate не проходит в каком-то или во всех потоках, соответственно, Count всегда больше нуля.


 
Сергей М. ©   (2006-11-03 13:21) [20]


> sleep(1000) не помогает


Это из другой оперы.

Если "виснет", то это означает, что как минимум один из твоих потоков завершаться упорно не желает.


 
Gear   (2006-11-03 13:35) [21]

Terminate проходит, если вот это повесить на кнопку
with ThreadList.LockList do
 try
    for i := 0 to Count - 1 do
       TThr(Items[i]).Terminate;
 finally
   UnlockList
 end;

и вывести куда-нибудь список threadid то я вижу что они сносятся.
Я думаю просто в тот момент когда происходит Form1.ThreadList.Remove(Self);
Тем самым циклом этот список залочен. И программа виснет.


 
Сергей М. ©   (2006-11-03 13:56) [22]


> Terminate проходит


А куда он денется ?

Метод Terminate не занимается ничем иным, кроме как взведением флажка FTerminated.


> вижу что они сносятся.


Значит никаких проблем с "залоченностью" нет.


> Тем самым циклом этот список залочен


Каким "тем" ?

Этим что ли

while True do
with ThreadList.LockList do
try
   if Count = 0 then Break;
finally
  UnlockList
end;

?

Ну ты ж видишь, что блокировка-разблокировка происходит в каждой итерации цикла, а длится каждая итерация тысячные доли секунды.

Так что не надо выдумывать небылицы - лучше приводи код метода TThr.Execute


 
Percent   (2006-11-03 14:48) [23]

Thread.Terminate;
Thread.WaitFor;
Tread.Free;


 
Сергей М. ©   (2006-11-03 14:54) [24]


> Percent   (03.11.06 14:48) [23]


> Tread.Free;


см. [13], 3-я строчка снизу


 
Gear   (2006-11-03 16:30) [25]

Легко могу даже весь код маленького проекта:


unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, StdCtrls, httpsend, ExtCtrls;

type
 TThr= class(TThread)
  private
  protected
  procedure Execute; override;
 public
  Furi:TstringList;
  constructor Create(uri:TstringList);
  destructor Destroy; override;
 end;

 TForm1 = class(TForm)
   Button1: TButton;
   Memo1: TMemo;
   Button2: TButton;
   Timer1: TTimer;
   ListBox1: TListBox;
   procedure Button1Click(Sender: TObject);
   procedure FormCreate(Sender: TObject);
   procedure Button2Click(Sender: TObject);
   procedure Timer1Timer(Sender: TObject);
   procedure FormClose(Sender: TObject; var Action: TCloseAction);
 private
   { Private declarations }
 public
   { Public declarations }
   Thr:TThr;
   ThreadList: TThreadList;
   procedure Term;
 end;

var
 Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
rssuri:TStringList;
begin
rssuri:=TStringList.Create;
rssuri.Add("http://www.ya.ru");
rssuri.Add("http://www.mail.ru");
rssuri.Add("http://www.rambler.ru");
Thr:=TThr.Create(uri);
uri.free;
end;

constructor TThr.Create(uri:TStringList);
begin
inherited Create(True);
Form1.ThreadList.Add(Self);
Furi:=Tstringlist.Create;
Furi.AddStrings(uri);
FreeOnTerminate:=True;
resume;
end;

destructor TThr.Destroy;
begin
if Furi<>nil then
 begin
  Furi.Free;
  Furi:=nil;
 end;
 Form1.ThreadList.Remove(Self);
 inherited Destroy;
end;

procedure TThr.Execute;
var
 s,uri:TStringList;
 HTTP : THTTPSend;
 good: boolean;
 k:integer;
begin
 s:=TStringList.Create;

 While not Terminated do begin

 for k:=0 to Frssuri.Count-1 do
 begin
      HTTP := THTTPSend.Create;
      HTTP.Protocol:="1.1";
      try
        good:=HTTP.HTTPMethod("GET",Furi.Strings[k]);
        if good then
           s.LoadFromStream(HTTP.Document);
      finally
         HTTP.Free;
         HTTP:=nil;
      end;
      Form1.Memo1.Lines.Add("html");
      if Terminated then
      begin
        Form1.Memo1.Lines.Add("term");
        break;
      end;
 end;
 sleep(1000);
 end;
 s.free;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 ThreadList:= TThreadList.Create;
end;

procedure TForm1.Term;
var
 i:integer;
begin
  with ThreadList, LockList do
   try
      for i := 0 to Count - 1 do
      begin
         TThr(Items[i]).Terminate;
      end;
   finally
     UnlockList
   end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
 Term;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
i:integer;
id:string;
begin
 listbox1.Clear;
 with ThreadList, LockList do
 try
   for i := 0 to Count - 1 do
   begin
     id := inttostr(TThr(Items[i]).ThreadID);
     listbox1.Items.Add(id);
   end;
 finally
   UnlockList
 end;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
ThreadList.Free;
end;

end.


Коммент к коду:
1) нажимаю button1, плодится поток который загружает html и отчитывается об этом в memo1.
2) Button2 терминирует все процессы и отчитывается словом term в тот же memo1.
3) По таймеру оббегается весь тредлист и id процессов выводит в listbox1.
Вот и вся программка.


 
Сергей М. ©   (2006-11-03 16:40) [26]


> Gear   (03.11.06 16:30) [25]


ты хоть что-нть слышал о небезопасности мультипоточного обращения к VCL-объектам ?


 
Джо ©   (2006-11-03 16:43) [27]

> [25] Gear   (03.11.06 16:30)
> Легко могу даже весь код маленького проекта:

Небольшое замечание. Следует сказать так:
"Легко могу даже весь код маленького неработающего проекта".


 
Gear   (2006-11-03 17:05) [28]

Наверное не слышал. Что там не так?


 
Сергей М. ©   (2006-11-03 17:09) [29]


> Что там не так?


Низя.

на то есть метод TThread.Synchronize()


 
Gear   (2006-11-03 17:17) [30]

да, это я так, забыл малость, но дело-то не в этом.


 
Сергей М. ©   (2006-11-03 17:20) [31]


> дело-то не в этом.


Сначала устрани явные ляпы, потоми и разговор будет предметный.


 
Gear   (2006-11-03 17:32) [32]

Это сделано.

procedure TThr.Execute;
...
Synchronize(Form1.trm);
...
Synchronize(Form1.html);
...

procedure TForm1.html;
begin
 Form1.Memo1.Lines.Add("html");
end;

procedure TForm1.trm;
begin
 Form1.Memo1.Lines.Add("term");
end;

Что ещё не так?


 
Дмитрий Белькевич ©   (2006-11-04 02:32) [33]

> While not Terminated do begin
1. этот цикл вообще крутиться?
2. Когда нажал на кнопку останова, Terminated взводится? Цикл останавливается?


 
Сергей М. ©   (2006-11-04 10:38) [34]

procedure TForm1.Term;
var
i:integer;
begin
 with ThreadList, LockList do
  try
     for i := 0 to Count - 1 do
     begin
        TThr(Items[i]).Terminate;
     end;
  finally
    UnlockList
  end;

 while True do begin
   with ThreadList.LockList do
   try
      if Count = 0 then
        Break
      else
        Application.ProcessMessages;
   finally
     UnlockList
   end;
 end;
end;


 
TStas ©   (2006-11-04 17:39) [35]

Ой, а подскажите чайнику: разьве потоки не умирают естественной смертью при завершении программы?


 
Leonid Troyanovsky ©   (2006-11-04 18:07) [36]


> TStas ©   (04.11.06 17:39) [35]
> Ой, а подскажите чайнику: разьве потоки не умирают естественной
> смертью при завершении программы?


Дык, а где уверенность, что она завершена?
Процесс жив, пока живет последний из потоков.

Кста, в 95 бывало, что потоки переживали и процесс.
Хотя, 2006 им-то уж не пережить.

--
Regards, LVT.


 
guav ©   (2006-11-04 19:13) [37]

> [35] TStas ©   (04.11.06 17:39)


При завершении первичного потока "естественным" путём (завершением выполннения блока begin...end программы или halt), из RTL будет вызвана ExitProcess, все остальные потоки будут завершены.


 
Gear   (2006-11-06 02:04) [38]

Они то завершатся, а вот с памятью его что-то станется. Вернее не освободится правильно. Поэтому-то и весь сырбор.


 
Gear   (2006-11-06 02:10) [39]

Да, всем спасибо, особенно Сергею М. Получилось то, что надо!



Страницы: 1 вся ветка

Текущий архив: 2006.12.17;
Скачать: CL | DM;

Наверх




Память: 0.57 MB
Время: 0.085 c
1-1162638387
312Kbps
2006-11-04 14:06
2006.12.17
Получить скрин окна по его хендлу !


15-1164776598
DelphiN!
2006-11-29 08:03
2006.12.17
Как изменить рабочую группу компьютера в локальной сети?


2-1164633388
vitv
2006-11-27 16:16
2006.12.17
Передача данных с контролов на форме в отчёт(Fast Report).


4-1155280631
ksa2002
2006-08-11 11:17
2006.12.17
Создание копии потока


8-1146831015
Fly
2006-05-05 16:10
2006.12.17
Нужно переконвертировать файл Excel в DBF