Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 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
1-1126683651
Tonich
2005-09-14 11:40
2005.10.02
Структура (запись)


1-1126665351
qwe
2005-09-14 06:35
2005.10.02
StringGrid


14-1126363891
Progamer
2005-09-10 18:51
2005.10.02
Турнир Футбольных прогнозов Мастаков


3-1124518722
Kinda
2005-08-20 10:18
2005.10.02
Восстановление удаленных записей


2-1124476576
TG
2005-08-19 22:36
2005.10.02
GIF