![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Как правильно закрыть все потоки закрывая программу? [D7, WinXP]
Gear © (2006-11-03 10:38:00)Из главного потока создаю несколько, которые занимаются закачкой из сети.
Нужно чтобы при закрытии основной программы, сначала закончились все потоки, и только затем завершался главный поток программы.
Делаю так:
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;
Такую функцию вешаю на кнопку и жду завершения потоков. Но что-то всё это не работает.
Подскажие пож-та как решить правильно мою задачу?
Gear (2006-11-06 02:10:00) [1]Да, всем спасибо, особенно Сергею М. Получилось то, что надо!
Gear (2006-11-06 02:04:00) [2]Они то завершатся, а вот с памятью его что-то станется. Вернее не освободится правильно. Поэтому-то и весь сырбор.
guav (2006-11-04 19:13:00) [3]> [35] TStas © (04.11.06 17:39)
При завершении первичного потока "естественным" путём (завершением выполннения блока begin...end программы или halt), из RTL будет вызвана ExitProcess, все остальные потоки будут завершены.
Leonid Troyanovsky (2006-11-04 18:07:00) [4]
> TStas © (04.11.06 17:39) [35]
> Ой, а подскажите чайнику: разьве потоки не умирают естественной
> смертью при завершении программы?
Дык, а где уверенность, что она завершена?
Процесс жив, пока живет последний из потоков.
Кста, в 95 бывало, что потоки переживали и процесс.
Хотя, 2006 им-то уж не пережить.
--
Regards, LVT.
TStas (2006-11-04 17:39:00) [5]Ой, а подскажите чайнику: разьве потоки не умирают естественной смертью при завершении программы?
Сергей М. (2006-11-04 10:38:00) [6]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;
Дмитрий Белькевич (2006-11-04 02:32:00) [7]> While not Terminated do begin
1. этот цикл вообще крутиться?
2. Когда нажал на кнопку останова, Terminated взводится? Цикл останавливается?
Gear (2006-11-03 17:32:00) [8]Это сделано.
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-03 17:20:00) [9]
> дело-то не в этом.
Сначала устрани явные ляпы, потоми и разговор будет предметный.
Gear (2006-11-03 17:17:00) [10]да, это я так, забыл малость, но дело-то не в этом.
Сергей М. (2006-11-03 17:09:00) [11]
> Что там не так?
Низя.
на то есть метод TThread.Synchronize()
Gear (2006-11-03 17:05:00) [12]Наверное не слышал. Что там не так?
Джо (2006-11-03 16:43:00) [13]> [25] Gear (03.11.06 16:30)
> Легко могу даже весь код маленького проекта:
Небольшое замечание. Следует сказать так:
"Легко могу даже весь код маленького неработающегопроекта".
Сергей М. (2006-11-03 16:40:00) [14]
> Gear (03.11.06 16:30) [25]
ты хоть что-нть слышал о небезопасности мультипоточного обращения к VCL-объектам ?
Gear (2006-11-03 16:30:00) [15]Легко могу даже весь код маленького проекта:
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 14:54:00) [16]
> Percent (03.11.06 14:48) [23]
> Tread.Free;
см. [13], 3-я строчка снизу
Percent (2006-11-03 14:48:00) [17]Thread.Terminate;
Thread.WaitFor;
Tread.Free;
Сергей М. (2006-11-03 13:56:00) [18]
> Terminate проходит
А куда он денется ?
Метод Terminate не занимается ничем иным, кроме как взведением флажка FTerminated.
> вижу что они сносятся.
Значит никаких проблем с "залоченностью" нет.
> Тем самым циклом этот список залочен
Каким "тем" ?
Этим что ли
while True do
with ThreadList.LockList do
try
if Count = 0 then Break;
finally
UnlockList
end;
?
Ну ты ж видишь, что блокировка-разблокировка происходит в каждойитерации цикла, а длится каждая итерация тысячные доли секунды.
Так что не надо выдумывать небылицы - лучше приводи код метода TThr.Execute
Gear (2006-11-03 13:35:00) [19]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:21:00) [20]
> sleep(1000) не помогает
Это из другой оперы.
Если "виснет", то это означает, что как минимум один из твоих потоков завершаться упорно не желает.