약 1000개의 웹사이트에서 내용을 가져오려고 합니다.
루프를 돌려서 쓰레드를 만드는데 쓰레드안에 Memo 객체를 생성하는데 (각 쓰레드마다)
처음 한개는 제대로 되는데 다음 쓰레드에서 'Control' has no parent windows
라는 에러가 나옵니다.
제 생각에는 쓰레드에서 생성한 memo 객체가 Free 되기전에 다시 생성해서
그런것 같은데 이 문제를 어떻게 해결해야 하나요 ?
고수님들 제발 부탁합니다.
아래는 소스입니다.
Form
unit PrimeForm;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, PgWhois, ComCtrls;
type
TForm1 = class(TForm)
NumEdit: TEdit;
SpawnButton: TButton;
Button1: TButton;
Button2: TButton;
Button3: TButton;
Button4: TButton;
Button5: TButton;
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Edit4: TEdit;
Edit5: TEdit;
Memo1: TMemo;
PgWhois1: TPgWhois;
Edit6: TEdit;
Memo2: TMemo;
Button6: TButton;
Memo3: TMemo;
Memo4: TMemo;
Edit7: TEdit;
procedure SpawnButtonClick(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure Button5Click(Sender: TObject);
procedure Button6Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses PrimeThread,PrimeThread2,PrimeThread3,PrimeThread4;
{$R *.DFM}
procedure TForm1.Button6Click(Sender: TObject);
var
nLoop, nMod, nCount : integer;
NewThread: TPrimeThread;
NewThread2: TPrimeThread2;
NewThread3: TPrimeThread3;
NewThread4: TPrimeThread4; <-- 같은 쓰레드를 4개를 만들었습니다.
한개로 해결할 수는 없나요 ?
begin
TRY
NewThread := TPrimeThread.Create(True);
NewThread.FreeOnTerminate := True;
NewThread.Terminate_Flag := True; <--- 쓰레드가 종됴 되었는가 Flag
NewThread2 := TPrimeThread2.Create(True);
NewThread2.FreeOnTerminate := True;
NewThread2.Terminate_Flag := True;
NewThread3 := TPrimeThread3.Create(True);
NewThread3.FreeOnTerminate := True;
NewThread3.Terminate_Flag := True;
NewThread4 := TPrimeThread4.Create(True);
NewThread4.FreeOnTerminate := True;
NewThread4.Terminate_Flag := True;
nLoop := 0;
WHILE nLoop <= Memo2.Lines.Count - 1 DO BEGIN
IF NewThread.Terminate_Flag THEN BEGIN
NewThread.TestNumber := nLoop;
NewThread.Resume;
INC(nLoop);
END;
IF NewThread2.Terminate_Flag THEN BEGIN
NewThread2.TestNumber := nLoop;
NewThread2.Resume;
INC(nLoop);
END;
IF NewThread3.Terminate_Flag THEN BEGIN
NewThread3.TestNumber := nLoop;
NewThread3.Resume;
INC(nLoop);
END;
IF NewThread4.Terminate_Flag THEN BEGIN
NewThread4.TestNumber := nLoop;
NewThread4.Resume;
INC(nLoop);
END;
END;
EXCEPT
NewThread.WaitFor;
NewThread.Free;
NewThread2.WaitFor;
NewThread2.Free;
NewThread3.WaitFor;
NewThread3.Free;
NewThread4.WaitFor;
NewThread4.Free;
END;
end;
end.
--- Thread 부분
unit PrimeThread;
interface
uses
Classes;
type
TPrimeThread = class(TThread)
private
{ Private declarations }
FTestNumber: integer;
FTestString: String;
FTerminate_Flag: Boolean;
Registry_Ymd: String;
Update_Ymd: String;
Valid_Ymd: String;
protected
procedure Execute; override;
procedure Check_Whois;
public
property TestNumber: integer write FTestNumber;
property TestString: String write FTestString;
property Terminate_Flag: Boolean read FTerminate_Flag write FTerminate_Flag;
end;
implementation
uses SysUtils, Dialogs, PrimeForm, stdctrls, PgWhois;
{ TPrimeThread }
procedure TPrimeThread.Check_Whois;
var
cMemo: TCustomMemo;
nLoop: Integer;
pWhois: TPgWhois;
begin
try
cMemo := TCustomMemo.Create(NIL);
pWhois := TPgWhois.Create(NIL);
cMemo.Lines.Text := PWhois.Whois;
FOR nLoop := 0 TO cMemo.Lines.Count - 1 DO BEGIN <-- 이 부분에서 Error
IF POS('Registed Date',cMemo.Lines.Strings[nLoop]) > 0 THEN
Registry_Ymd := COPY(cMemo.Lines.Strings[nLoop],Length
(cMemo.Lines.Strings[nLoop])-7,8);
IF POS('Updated Date',cMemo.Lines.Strings[nLoop]) > 0 THEN
Update_Ymd := COPY(cMemo.Lines.Strings[nLoop],Length
(cMemo.Lines.Strings[nLoop])-7,8);
IF POS('Valid Date',cMemo.Lines.Strings[nLoop]) > 0 THEN
Valid_Ymd := COPY(cMemo.Lines.Strings[nLoop],Length
(cMemo.Lines.Strings[nLoop])-7,8);
END;
finally
cMemo.free; pWhois.Free;
end;
end;
procedure TPrimeThread.Execute;
var
nloop: integer;
begin
{ Place thread code here }
Showmessage(inttostr(FtestNumber));
Terminate_Flag := False;
Form1.PgWhois1.Request := Form1.Memo2.Lines.Strings[FTestNumber];
Synchronize(Check_Whois); <--- 이렇게 사용하는 것이 맞나요 ?
Terminate_Flag := True; <-- 쓰레드가 끝나면 True 설정
end;
end.
먼저 쓰레드 내에서 cMemo라는 TCustomMemo를 사용하셨는데.. 이의 용도가
단순히 lines 속성을 사용하기 위해서였다면, 굳이 TCustomMemo를 사용하지
말고, TStringList 를 사용하시는 것이 좋겠지요..
그리고, 같은 쓰레드 클래스를 각기 이름을 달리하여 네개를 선언하셨더군요...
> NewThread: TPrimeThread;
> NewThread2: TPrimeThread2;
> NewThread3: TPrimeThread3;
> NewThread4: TPrimeThread4; <-- 같은 쓰레드를 4개를 만들었습니다.
다음과 같이 간단하게 줄일 수 있겠죠...
NewThread, NewThread2, NewThread3, NewThread4: TPrimeThread;
제가 코드를 정확하게 다 이해를 못했는데,
쓰레드에서 굳이 Terminate_Flag라는 변수를 만들어서 사용할 필요가 없습니다.
Terminated라는 속성이 이미 있습니다. 이 속성을 검사해서, 쓰레드가 종료되었는지
알 수 있습니다.
또 쓰레드의 Execute 부분에서 메인 폼의 객체를 그냥 접근 하셨는데,
메인 폼의 객체를 접근하는 부분을 따로 함수로 만들고 그 함수를
Synchronize 해야 합니다. ^^;
일단 눈에 보이는 부분만 말씀드렸는데, 코딩하시는데 도움이 되었으면 합니다.
초보 wrote:
> 약 1000개의 웹사이트에서 내용을 가져오려고 합니다.
> 루프를 돌려서 쓰레드를 만드는데 쓰레드안에 Memo 객체를 생성하는데 (각 쓰레드마다)
> 처음 한개는 제대로 되는데 다음 쓰레드에서 'Control' has no parent windows
> 라는 에러가 나옵니다.
>
> 제 생각에는 쓰레드에서 생성한 memo 객체가 Free 되기전에 다시 생성해서
> 그런것 같은데 이 문제를 어떻게 해결해야 하나요 ?
>
> 고수님들 제발 부탁합니다.
>
> 아래는 소스입니다.
>
> Form
>
> unit PrimeForm;
>
> interface
>
> uses
> Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
> StdCtrls, PgWhois, ComCtrls;
>
> type
> TForm1 = class(TForm)
> NumEdit: TEdit;
> SpawnButton: TButton;
> Button1: TButton;
> Button2: TButton;
> Button3: TButton;
> Button4: TButton;
> Button5: TButton;
> Edit1: TEdit;
> Edit2: TEdit;
> Edit3: TEdit;
> Edit4: TEdit;
> Edit5: TEdit;
> Memo1: TMemo;
> PgWhois1: TPgWhois;
> Edit6: TEdit;
> Memo2: TMemo;
> Button6: TButton;
> Memo3: TMemo;
> Memo4: TMemo;
> Edit7: TEdit;
> procedure SpawnButtonClick(Sender: TObject);
> procedure Button1Click(Sender: TObject);
> procedure Button2Click(Sender: TObject);
> procedure Button3Click(Sender: TObject);
> procedure Button4Click(Sender: TObject);
> procedure Button5Click(Sender: TObject);
> procedure Button6Click(Sender: TObject);
> private
> { Private declarations }
> public
> { Public declarations }
> end;
>
> var
> Form1: TForm1;
>
> implementation
> uses PrimeThread,PrimeThread2,PrimeThread3,PrimeThread4;
>
> {$R *.DFM}
>
> procedure TForm1.Button6Click(Sender: TObject);
> var
> nLoop, nMod, nCount : integer;
> NewThread: TPrimeThread;
> NewThread2: TPrimeThread2;
> NewThread3: TPrimeThread3;
> NewThread4: TPrimeThread4; <-- 같은 쓰레드를 4개를 만들었습니다.
> 한개로 해결할 수는 없나요 ?
> begin
> TRY
> NewThread := TPrimeThread.Create(True);
> NewThread.FreeOnTerminate := True;
> NewThread.Terminate_Flag := True; <--- 쓰레드가 종됴 되었는가 Flag
> NewThread2 := TPrimeThread2.Create(True);
> NewThread2.FreeOnTerminate := True;
> NewThread2.Terminate_Flag := True;
> NewThread3 := TPrimeThread3.Create(True);
> NewThread3.FreeOnTerminate := True;
> NewThread3.Terminate_Flag := True;
> NewThread4 := TPrimeThread4.Create(True);
> NewThread4.FreeOnTerminate := True;
> NewThread4.Terminate_Flag := True;
> nLoop := 0;
> WHILE nLoop <= Memo2.Lines.Count - 1 DO BEGIN
> IF NewThread.Terminate_Flag THEN BEGIN
> NewThread.TestNumber := nLoop;
> NewThread.Resume;
> INC(nLoop);
> END;
> IF NewThread2.Terminate_Flag THEN BEGIN
> NewThread2.TestNumber := nLoop;
> NewThread2.Resume;
> INC(nLoop);
> END;
> IF NewThread3.Terminate_Flag THEN BEGIN
> NewThread3.TestNumber := nLoop;
> NewThread3.Resume;
> INC(nLoop);
> END;
> IF NewThread4.Terminate_Flag THEN BEGIN
> NewThread4.TestNumber := nLoop;
> NewThread4.Resume;
> INC(nLoop);
> END;
> END;
> EXCEPT
> NewThread.WaitFor;
> NewThread.Free;
> NewThread2.WaitFor;
> NewThread2.Free;
> NewThread3.WaitFor;
> NewThread3.Free;
> NewThread4.WaitFor;
> NewThread4.Free;
> END;
> end;
>
> end.
>
> --- Thread 부분
> unit PrimeThread;
>
> interface
>
> uses
> Classes;
>
> type
> TPrimeThread = class(TThread)
> private
> { Private declarations }
> FTestNumber: integer;
> FTestString: String;
> FTerminate_Flag: Boolean;
> Registry_Ymd: String;
> Update_Ymd: String;
> Valid_Ymd: String;
> protected
> procedure Execute; override;
> procedure Check_Whois;
> public
> property TestNumber: integer write FTestNumber;
> property TestString: String write FTestString;
> property Terminate_Flag: Boolean read FTerminate_Flag write FTerminate_Flag;
> end;
>
> implementation
>
> uses SysUtils, Dialogs, PrimeForm, stdctrls, PgWhois;
> { TPrimeThread }
>
> procedure TPrimeThread.Check_Whois;
> var
> cMemo: TCustomMemo;
> nLoop: Integer;
> pWhois: TPgWhois;
> begin
> try
> cMemo := TCustomMemo.Create(NIL);
> pWhois := TPgWhois.Create(NIL);
> cMemo.Lines.Text := PWhois.Whois;
> FOR nLoop := 0 TO cMemo.Lines.Count - 1 DO BEGIN <-- 이 부분에서 Error
> IF POS('Registed Date',cMemo.Lines.Strings[nLoop]) > 0 THEN
> Registry_Ymd := COPY(cMemo.Lines.Strings[nLoop],Length
> (cMemo.Lines.Strings[nLoop])-7,8);
> IF POS('Updated Date',cMemo.Lines.Strings[nLoop]) > 0 THEN
> Update_Ymd := COPY(cMemo.Lines.Strings[nLoop],Length
> (cMemo.Lines.Strings[nLoop])-7,8);
> IF POS('Valid Date',cMemo.Lines.Strings[nLoop]) > 0 THEN
> Valid_Ymd := COPY(cMemo.Lines.Strings[nLoop],Length
> (cMemo.Lines.Strings[nLoop])-7,8);
> END;
> finally
> cMemo.free; pWhois.Free;
> end;
> end;
>
> procedure TPrimeThread.Execute;
> var
> nloop: integer;
> begin
> { Place thread code here }
> Showmessage(inttostr(FtestNumber));
> Terminate_Flag := False;
> Form1.PgWhois1.Request := Form1.Memo2.Lines.Strings[FTestNumber];
> Synchronize(Check_Whois); <--- 이렇게 사용하는 것이 맞나요 ?
> Terminate_Flag := True; <-- 쓰레드가 끝나면 True 설정
> end;
>
> end.
>