Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2006.12.17;
Скачать: [xml.tar.bz2];

Вниз

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

 
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;
Скачать: [xml.tar.bz2];

Наверх





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


5-1145023755
SMAC
2006-04-14 18:09
2006.12.17
Binary component


2-1164751573
alexdemche
2006-11-29 01:06
2006.12.17
Добавление файлов в Recent Files


15-1164350012
Zhekson
2006-11-24 09:33
2006.12.17
Чувствительность к регистру


2-1164590343
NovaC
2006-11-27 04:19
2006.12.17
Закрыть окно консоли в Delphi





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский