Текущий архив: 2005.10.02;
Скачать: CL | DM;
Вниз
idHTTP и потоки Найти похожие ветки
← →
leonidus © (2005-06-07 08:31) [0]В продолжении темы предотвращения гонок в потоках, хочц разобраться вот в чем. Использую idHTTP в потоке. Пишу:
.....
.....
TThread_download = class(TThread)
private
{ Private declarations }
protected
URL:string;
path:string;
size:longint;
FMaxProgress:integer;
FProgress:integer;
Log_ID:string;
Number:word;
procedure Execute; override;
procedure Log;
end;
....
var
t_download:TThread_download;
....
procedure TThread_download.Execute;
var
Response: TFileStream;
HTTP:TIdHTTP;
begin
try
Response := TFileStream.Create(path, fmCreate);
HTTP:= TIdHTTP.Create(nil);
try
HTTP.Get(URL, Response);
Size:=Response.Size;
finally
HTTP.Free;
Response.Free;
end;
Synchronize(Log);
except
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
i:integer;
begin
for i:=1 to 4 do
begin //запускаем 4 потока
t_download:=TThread_download.Create(true);
t_download.FreeOnTerminate:=true;
t_download.URL:=turn[i]; //берем ссылку из очереди
t_download.path:=path[i]; //берем путь куда сохранить
t_download.Resume;
end;
end;
Это примерный код. Вопрос такой, как мне в произвольный момент времени остановить произвольный поток. По сути один раз запустив, я отправляю поток в "свободное плавание" и теряю над ним управление. Может есть какой-то уникальный идентификатор у каждого потока, по которому к этому потоку можно обратиться и убить его принудительно? Но тут еще возникает проблема с самим компонентом idHTTP, убив поток в котором создан этот компонент умрет ли idHTTP если в этот момент он производит скачивание?
← →
Digitman © (2005-06-07 08:53) [1]
> как мне в произвольный момент времени остановить произвольный
> поток
остановить или завершить ?
остановить - см. TThread.Suspend
завершить (принудительно) - TerminateThread()
> теряю над ним управление
нет, не теряешь.
несмотря на то что idHTTP.Get() есть блокирующий метод, можно повлиять на его работу так чтобы он вернул управление досрочно, например, завершился с исключением ... для этого достаточно в другом трэде закрыть гнездо (closehandle), которое используется объектом idHTTP (см. TidHTTP.Binding.Handle)
> есть какой-то уникальный идентификатор у каждого потока,
> по которому к этому потоку можно обратиться и убить его
> принудительно?
есть.
см. TThread.Handle, его значение можно передать параметром ф-ции TerminateThread()
> тут еще возникает проблема с самим компонентом idHTTP, убив
> поток в котором создан этот компонент умрет ли idHTTP если
> в этот момент он производит скачивание?
в твоем примере - нет.
← →
leonidus © (2005-06-07 09:08) [2]Мне нужно именно завершить поток принудительно. Digitman как мне переделать пример?
← →
Digitman © (2005-06-07 09:59) [3]сделай HTTP полемTThread_download
тогда
try
closesocket(t_download.HTTP.Binding.Handle);
except
end;
← →
Alexander Panov © (2005-06-07 10:11) [4]У idHTTP есть свой метод для закрытия сокета - DisconnectSocket.
← →
leonidus © (2005-06-07 10:46) [5]>Digitman
сделал так:
TThread_download = class(TThread)
private
{ Private declarations }
protected
URL:string;
path:string;
size:longint;
FMaxProgress:integer;
FProgress:integer;
Log_ID:string;
Number:word;
HTTP:TIdHTTP;
procedure Execute; override;
procedure Log;
end;
но какой из потоков будет остановлен если использовать
try
closesocket(t_download.HTTP.Binding.Handle);
except
end;
?
Мне же нужно явно указать какой поток убить.
>Alexander Panov
Да, знаю про такой метод, но как его применить именно к нужному экземпляру потока?
Я вообще технологию потока с работающим idHTTP правильно понял, что придется убивать и сам поток и отдельно созданный в нем idHTTP? Если так, то какая тут последовательность? Сначала убить idHTTP через скажем DisconnectSocket а потом сам поток, но через что?
← →
leonidus © (2005-06-07 10:48) [6]и потом Digitman, попробовал использовать t_download.HTTP.Binding.Handle но у HTTP нет метода Binding... у меня 9-я Indy а у вас какая?
← →
Digitman © (2005-06-07 11:07) [7]
> нужно явно указать какой поток убить
в твоем примере это t_download
> но у HTTP нет метода Binding
ну посмотри сам, я не помню у кого там binding есть ... может у Connection
← →
leonidus © (2005-06-07 11:58) [8]> нужно явно указать какой поток убить
>в твоем примере это t_download
ну то что t_download надо убить это да, но у него будет 4 экземпляра (я 4 потока запускаю), мне например в какой-то момент нужно убить 3-й поток как это сделать?
← →
Alexander Panov © (2005-06-07 12:01) [9]leonidus © (07.06.05 11:58) [8]
как это сделать?
А ты для работы с объектом любого класса как работаешь? Правильно - по ссылке.
Вот и на созданный объект-поток тебе тоже нужна ссылка.
А как ты ее сохранишь - это уже твои проблемы.
В массив ли занесешь, в TList, или еще как...
← →
leonidus © (2005-06-07 12:10) [10]>Alexander Panov простите но я не понимаю о чем вы :( я раньше программировал потоки тупо, т.е. если у меня 4 потока я создавал 4 переменных класса TThread_download :t1,t2,t3,t4 или и того хлеще 4 класса TThread_download: TThread_download1, TThread_download2, TThread_download3, TThread_download4 и тогда каждым из них было очень просто управлять, т.к. они уже проименованны. Сейчас для того что бы не дублировать один и тот же код и жестко не ограничивать себя кол-вом потоков решил просто запускать несколько экземпляров одного класса, но тогда я "теряю" их сразу после запуска, не могу ни к одному из них явно обратиться. Подскажите пожалуйста как изменить первоначальный код.
← →
Digitman © (2005-06-07 12:17) [11]
> тогда я "теряю" их сразу после запуска
ничего ты не теряешь
TThread_download = class(TThread)
private
FThreads: array[1..4] of TThread_download;
..
end;
procedure TForm1.Button1Click(Sender: TObject);
var
i:integer;
begin
for i:=1 to 4 do
begin //запускаем 4 потока
FThreads[i]:=TThread_download.Create(true);
with FThreads[i] do
begin
FreeOnTerminate:=true;
URL:=turn[i]; //берем ссылку из очереди
path:=path[i]; //берем путь куда сохранить
Resume;
end;
end;
← →
Alexander Panov © (2005-06-07 12:18) [12]leonidus © (07.06.05 12:10) [10]
Схематично:
var
ThrList: TList;
------------
Создаешь список для хранения объектов.
List := ThrList.Create;
------------
Создаешь сами объекты:
for i := 0 to N do
begin
List.Add(TMyThread.Create);
end;
------------
В случае необходимости обращаешься к объекту, например:
TMyThread(List[i]).Terminate;
Вообще, у меня был пример работы с idHTTP в потоке.
Сейчас найду.
← →
Alexander Panov © (2005-06-07 12:52) [13]
unit uHTTPThread;
interface
uses
Classes, IdHTTP, SyncObjs,windows;
type
THTTPThread = class(TThread)
private
FH: TIdHTTP;
FUrl: String;
FEvent: TEvent;
FResult: String;
function GetErrorCode: Integer;
protected
procedure Execute; override;
public
constructor Create;
destructor Destroy;override;
procedure Release;
function Get(const Url: String; aWait: Boolean): String;
property ErrorCode: Integer read GetErrorCode;
end;
implementation
{ THTTPThread }
constructor THTTPThread.Create;
begin
inherited Create(True);
FEvent := TEvent.Create(nil,True,False,"");
FreeOnTerminate := True;
Resume;
end;
destructor THTTPThread.Destroy;
begin
FH.Free;
FEvent.Free;
inherited;
end;
procedure THTTPThread.Execute;
begin
FH := TidHTTP.Create(nil);
FResult :="";
Suspend;
while not Terminated do
begin
if Terminated then Exit;
try
try
FResult := FH.Get(Furl);
except
FResult :="";
end;
finally
try
FH.DisconnectSocket;
except
end;
end;
FEvent.SetEvent;
Suspend;
if Terminated then Exit;
end;
end;
function THTTPThread.Get(const Url: String;aWait: Boolean): String;
begin
Result := "";
FUrl := Url;
FEvent.ResetEvent;
Resume;
if aWait then
begin
FEvent.WaitFor(INFINITE);
Result := FResult;
end;
end;
function THTTPThread.GetErrorCode: Integer;
begin
Result := FH.ResponseCode;
end;
procedure THTTPThread.Release;
begin
FH.DisconnectSocket;
Terminate;
Resume;
end;
end.
-------------------
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs,
uHTTPThread, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Memo1: TMemo;
Button3: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
HTTPList: array[0..3] of THTTPThread;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
begin
for i := 0 to 3 do HTTPList[i] := THTTPThread.Create;
end;
procedure TForm1.Button2Click(Sender: TObject);
var
i: Integer;
begin
memo1.Lines.Add(HTTPList[0].Get("http://www.delphimaster.ru/cgi-bin/forum.pl?last=11",True));
if HTTPList[0].ErrorCode<>200 then ShowMessage("Error");
for i := 0 to 3 do HTTPList[i].Get("http://www.delphimaster.ru/cgi-bin/forum.pl?last=11",True);
end;
procedure TForm1.Button3Click(Sender: TObject);
var
i: Integer;
begin
for i := 0 to 3 do HTTPList[i].Release;
end;
end.
← →
Alexander Panov © (2005-06-07 12:59) [14]Вот здесь:
procedure THTTPThread.Release;
begin
FH.DisconnectSocket;
Terminate;
Resume;
end;
надо заменить наprocedure THTTPThread.Release;
begin
try
FH.DisconnectSocket;
except
end;
Terminate;
Resume;
end;
← →
leonidus © (2005-06-07 13:58) [15]Большое спасибо за помошь, сейчас попробую.
Страницы: 1 вся ветка
Текущий архив: 2005.10.02;
Скачать: CL | DM;
Память: 0.52 MB
Время: 0.029 c