Q&A

  • 쓰레드문제 해결좀 해주세요...
약 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.



1  COMMENTS
  • Profile
    한원희 2001.02.07 05:56
    답변이라고는 할 수 없지만, 몇 가지 문제점을 집어 보겠습니다.



    먼저 쓰레드 내에서 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.

    >