My code has to download the source code of a page and parse it for URLs. I want it to ask for number which is increased inside the critical section. My problem happens on thread termination.
Main form code:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, OverbyteIcsWndControl, OverbyteIcsHttpProt, StdCtrls,Unit2, Spin;
const
WM_DATA_IN_BUF = WM_APP + 1000;
type
TForm1 = class(TForm)
HttpCli1: THttpCli;
Button1: TButton;
ListBox1: TListBox;
Memo1: TMemo;
Button2: TButton;
SpinEdit1: TSpinEdit;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
FStringSectInit: boolean;
FGoogle: array [0..2] of TGoogle;
FStringBuf: TStringList;
FLink:integer;
procedure HandleNewData(var Message: TMessage); message WM_DATA_IN_BUF;
public
StringSection: TRTLCriticalSection;
property StringBuf: TStringList read FStringBuf write FStringBuf;
property Link: integer read FLink write FLink;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var i:integer;
begin
if not FStringSectInit then
begin
form1.FLink:=0;
InitializeCriticalSection(StringSection);
FStringBuf := TStringList.Create;
FStringSectInit := true;
for i:=0 to 2 do
begin
FGoogle[i]:= TGoogle.Create(true);
SetThreadPriority(FGoogle[i].Handle, THREAD_PRIORITY_BELOW_NORMAL);
FGoogle[i].Resume;
end;
end;
end;
procedure TForm1.HandleNewData(var Message: TMessage);
var k,i,s:integer;
begin
if FStringSectInit then
begin
EnterCriticalSection(StringSection);
s:=flink;
inc(s,8);
flink:=s;
memo1.Lines.Add(FStringBuf.Text);
FStringBuf.Clear;
LeaveCriticalSection(StringSection);
{Now trim the Result Memo.}
end;
if form1.Memo1.Lines.Count>20 then
for k:=0 to 2 do
begin
fgoogle[k].Terminate;
fgoogle[k].WaitFor;
fgoogle[k].Free;
FStringBuf.Free;
DeleteCriticalSection(StringSection);
FStringSectInit := false;
memo1.Lines.Add('Thread is done: ' + inttostr(k));
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
listbox1.Clear;
end;
end.
Worker thread code:
unit Unit2;
interface
uses
Classes,Windows,IDHTTP, OverbyteIcsWndControl, StdCtrls,OverbyteIcsHttpProt,SysUtils,Dialogs;
type
TGoogle = class(TThread)
private
google:TStringList;
Upit:string;
Broj:integer;
Buffer : TStringList;
httpcli1:THTTPcli;
protected
procedure parsegoogleapi;
procedure SkiniSors;
procedure Execute; override;
public
property StartNum: integer read Broj write Broj;
end;
implementation
uses unit1,StrUtils;
function ExtractText(const Str, Delim1, Delim2: string; PosStart: integer; var PosEnd: integer): string;
var
pos1, pos2: integer;
begin
Result := '';
pos1 := PosEx(Delim1, Str, PosStart);
if pos1 > 0 then
begin
pos2 := PosEx(Delim2, Str, pos1 + Length(Delim1));
if pos2 > 0 then
begin
PosEnd := pos2 + Length(Delim2);
Result := Copy(Str, pos1 + Length(Delim1), pos2 - (pos1 + Length(Delim1)));
end;
end;
end;
function ChangeString(const Value: string; replace:string): string;
var i: Integer;
begin
Result := '';
for i := 1 to Length(Value) do
if Value[i] = ' ' then
Result := Result + replace
else
Result := Result + Value[i]
end;
(*Ovo je procedura za skidanje sorsa*)
procedure TGoogle.SkiniSors;
var
criter:string;
begin
HttpCli1:=THttpCli.Create(nil);
google:=TStringList.Create;
criter:= ChangeString(Upit,'%20');
With HttpCli1 do begin
URL := 'http://ajax.googleapis.com/ajax/services/search/web?v=1.0&start=' + inttostr(broj) + '&rsz=large&q=rocksongs';
RequestVer := '1.1';
Connection := 'Keep-Alive';
RcvdStream := TMemoryStream.Create;
try
Get;
except
RcvdStream.Free;
Exit;
(*How can I terminate thread here if I get error*)
end;
RcvdStream.Seek(0,0);
google.LoadFromStream(RcvdStream);
RcvdStream.Free;
ParseGoogleApi;
end;
end;
procedure TGoogle.ParseGoogleApi;
var Pos: integer;
sText: string;
begin
Buffer:= TStringList.Create;
sText := ExtractText(google.Text, '"url":"', '","visibleUrl"', 1, Pos);
while sText <> '' do
begin
buffer.Add(sText);
sText := ExtractText(google.Text, '"url":"', '","visibleUrl"', Pos, Pos);
end;
google.Clear;
end;
procedure TGoogle.Execute;
var i:integer;
begin
while not terminated do
begin
EnterCriticalSection(Form1.StringSection);
Broj:=form1.Link;
skinisors;
Form1.StringBuf.Add(buffer.Text);
LeaveCriticalSection(Form1.StringSection);
PostMessage(Form1.Handle, WM_DATA_IN_BUF, 0, 0);
end;
Google.Free;
Buffer.Free;
httpcli1.Free;
end;
end.
Also, how do I deal with timeouts with THttpCli1
? Is it a smart idea to use Timer
inside threads?
EnterCriticalSection
andLeaveCriticalSection
are withintry..finally
to clean up properly in the event of exceptional situations. – Jesse C. Slicer Feb 10 '12 at 16:30