Delphi Thread(3)

TThread는 우리가 항상 작업 라인과 주 라인의 구분을 상세하게 설명하고 작업 라인은 일부 백엔드 조작을 책임진다. 예를 들어 우편물을 받는 것이다.
메인 라인은 인터페이스의 일부 디스플레이를 책임진다.
작업 라인의 장점은 때때로 말하지 않아도 알 수 있다. 당신의 메인 인터페이스는 어떠한 조작에도 응답할 수 있지만, 뒤의 라인은 묵묵히 일하고 있다.
VCL에서 작업 루틴이 Excute 방법에서 실행되려면 TThread에서 하나의 클래스를 계승하고 Execute 방법을 덮어써야 한다. 이 방법에서 모든 코드는 다른 루틴에서 실행된다. 이외에 당신의 루틴 클래스의 다른 방법은 모두 메인 루틴에서 실행된다. 구조 방법, 분석 방법, Resume 등을 포함하여 많은 사람들이 이 점을 소홀히 한다.가장 간단한 스레드 클래스는 다음과 같습니다. TMyThread =class(Tthread) protected procedure Execute;override; end; Execute의 코드에는 기술 요점이 하나 있는데, 만약 당신의 코드가 실행 시간이 매우 짧다면, 이렇게 슬립(1000)은 상관없다.만약 이렇게 Sleep(10000), 10초라면 당신은 직접 이렇게 쓸 수 없습니다. 이 10초를 10개의 1초로 나누고Terminated 속성을 판단해야 합니다. 다음처럼:procedure TMy Thread.Execute; var    i: Integer; begin    for i := 0 to 9 do       if not Terminated then         Sleep(1000)      else         Break; end; 이렇게 쓰면 뭐가 좋을까,
프로그램을 닫으려면 닫을 때 MyThread를 사용하십시오.Free, 이 때 라인이 바로 끝나지 않았습니다. WaitFor를 호출해서 Execute가 실행된 후에야 풀 수 있습니다.
너의 프로그램은 반드시 10초를 기다려야만 비로소 꺼질 수 있다. 견딜 수 있겠니?만약 위와 같이 쓰면, 프로그램이 닫힐 때, Free를 호출한 후, 최대 1초만 더 기다리면 닫힌다.
왜?답은 루틴 종류의Destroy에서 찾아야 한다. 루틴 방법을 먼저 사용하는데, 이 방법에서Terminated를True로 설정한다. (단지 이것뿐이다. 많은 사람들이 루틴을 끝낸다고 생각하지만 사실은 그렇지 않다.)
이 모든 것은 주 루트에서 실행되기 때문에 Execute와 병행적으로 실행된다는 것을 기억하십시오.Terminated 속성이 Ture인 이상 Execute에서 판단한 후에 Break은 물론 Execute가 실행되고 루틴 클래스도 정상적으로 방출됩니다.또는 어떤 사람들은 TThread가 Free On Terminate 속성을 True로 설정하면 루틴 종류가 자동으로 방출된다고 말한다.당신의 라인이 수행하는 임무가 매우 간단하지 않으면, 이 속성을 상관하지 마세요. 모든 것을 당신이 조작해야만 라인을 더욱 유연하고 강하게 할 수 있습니다.다음 문제는 어떻게 작업 라인과 주 라인이 잘 통신할 수 있는지입니다. 주 라인은 반드시 작업 라인의 통지를 받아야만 응답할 수 있는 경우가 많습니다.예를 들어 메일을 수신하면 작업 라인이 서버에 메일을 받는다. 수령이 끝난 후에 메인 라인이 얼마나 많은 메일을 받았는지 알려줘야 메인 라인이 창을 뜨고 사용자에게 알릴 수 있다.VCL에서 우리는 두 가지 방법을 사용할 수 있다. 하나는 메인 라인의 창에 메시지를 보내는 것이고, 다른 하나는 비동기 이벤트를 사용하는 것이다.
첫 번째 방법은 사실 두 번째 방법이 편리하게 오지 않는다.루틴 클래스의 OnTerminate 이벤트를 생각해 보세요. 이 이벤트는 루틴 함수의 창고에서 발생하지만 주 루틴에서 실행됩니다.사실 진정한 스레드 함수는 이:function ThreadProc(Thread: Tthread):Integer;함수 안에 Thread가 있다.Execute, 이것이 바로 Execute가 다른 라인에서 실행되는 이유입니다. 이 방법이 실행된 후에 다음과 같은 문장이 있습니다: Thread.DoTerminate; 스레드류의DoTerminate 방법은if Assigned(FONTerminate)then Synchronize(Call On Terminate)이다.
분명히 Synchronize 방법은Call On Terminate를 주 라인에서 실행하게 하고 Call On Terminate의 코드는 사실:if Assigned(FON Terminate)then FON Terminate(Self)이다.Execute 메서드가 실행되는 즉시 OnTerminate 이벤트가 발생합니다.그러나 한 가지 주의해야 할 것은 On Terminate 사건이 발생한 후에 루틴 종류가 반드시 방출되는 것은 아니며 Free On Terminate가True가 된 후에만Thread가 된다는 것이다.Free.ThreadProc 함수를 보면 알 수 있습니다.Onterminate 이벤트에 따라 비동기식 이벤트를 설계할 수 있습니다.Synchronize 방법은 파라미터가 없는 방법 유형으로만 전송될 수 있지만 우리의 이벤트는 항상 파라미터를 가지고 있어야 한다. 이것은 조금만 생각하면 해결될 수 있다. 즉, 온라인 클래스에 파라미터를 저장하고 이벤트를 촉발하기 전에 파라미터를 설정한 다음에 비동기 이벤트를 호출한다. 파라미터가 복잡하면 기록이나 클래스로 실현할 수 있다.가령 이렇게 하면 위의 코드가 1초에 한 번씩 자고 라인이 바깥으로 사건을 일으킨다고 가정하면 우리의 클래스는 이렇게 설계할 수 있다.
TSecondEvent = procedure (Second: Integer) of object;
TMyThread = class(TThread)
private
FSecond: Integer;
FSecondEvent: TSecondEvent;
procedure CallSecondEvent;
protected
procedure Execute; override;
public
property SencondEvent: TSecondEvent read FSecondEvent
write FSecondEvent;
end;

{ TMyThread }

procedure TMyThread.CallSecondEvent;
begin
if Assigned(FSecondEvent) then
FSecondEvent(FSecond);
end;

procedure TMyThread.Execute;
var
i: Integer;
begin
for i := 0 to 9 do
if not Terminated then
begin
Sleep(1000);
FSecond := i;
Synchronize(CallSecondEvent);
end
else
Break;
end; 
               :

procedure TForm1.Button1Click(Sender: TObject);
begin
MyThread := TMyThread.Create(true);
MyThread.OnTerminate := ThreadTerminate;
MyThread.SencondEvent := SecondEvent;
MyThread.Resume;
end;

procedure TForm1.ThreadTerminate(Sender: TObject);
begin
ShowMessage('ok');
end;

procedure TForm1.SecondEvent(Second: Integer);
begin
Edit1.Text := IntToStr(Second);
end;

                Edit     。

              Execute  ,                  。        ,             ,            ,Execute        ,           ,                 。         ,    ,        ,       ,        , 

        :

type
TMyClass = class
private
FSecond: Integer;
public
procedure SleepOneSecond;
end;

TMyThread = class(TThread)
private
FMyClass: TMyClass;
protected
procedure Execute; override;
public
constructor MyCreate(CreateSuspended: Boolean);
destructor Destroy; override;
end;

implementation

{ TMyThread }

constructor TMyThread.MyCreate(CreateSuspended: Boolean);
begin
inherited Create(CreateSuspended);
FMyClass := TMyClass.Create;
end;

destructor TMyThread.Destroy;
begin
FMyClass.Free;
FMyClass := nil;
inherited;
end;

procedure TMyThread.Execute;
var
i: Integer;
begin
for i := 0 to 9 do
FMyClass.SleepOneSecond;
end;

{ TMyClass }

procedure TMyClass.SleepOneSecond;
begin
FSecond := 0;
Sleep(1000);
end;

end. 

             :

procedure TForm1.Button1Click(Sender: TObject);
begin
MyThread := TMyThread.MyCreate(true);
MyThread.OnTerminate := ThreadTerminate;
MyThread.Resume;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
MyThread.Free;
end;

 
먼저 Button1을 누르면 라인을 만들고 Button2를 누르면 이 종류를 방출합니다. 어떤 상황이 나타날까요? 불법 방문, 네, My Thread.Free 때 MyClass가 풀렸어요. FMyClass.Free; FMyClass := nil; 이때 Execute가 실행되고 MyClass를 호출하는 방법은 당연히 위법 방문이 발생한다.이런 상황에 대해 어떤 방법으로 방지할 수 있습니까? 저는 온라인 클래스에서 한 구성원을 사용하고 FFinished라고 가정하면 Execute 방법에서 다음과 같은 형식이 있다고 생각합니다. FFinished: = False.try //... ... finally FFinished := True; End; 이어서 온라인 클래스의Destroy에는 다음과 같은 형식이 있다. While not Ffinished do Sleep(100).MyClass.Free; 이렇게 하면 MyClass가 정확하게 석방될 수 있다.스레드는 매우 유용한 기술이다.그러나 잘못 사용하면 골치가 아프다.CSDN 포럼에서 몇몇 사람들이 내 창이 라인에서 왜 잘못되었는지, 메인 라인이 다른 라인에 어떻게 메시지를 보냈는지 물어보는 것을 보았다. 사실 우리는 라인이 어렵다고 불평할 때 우리가 사용하는 방법이 맞는지 생각해야 한다.
정확한 사용 규칙만 따르면, 라인은 사실 매우 간단하다.후기 위에 코드가 좀 이상하다: FMyClass.Free; FMyClass := nil;FMyClass만 쓰면Flee, 루틴 클래스에 이상이 생기지 않습니다. 즉 FMyClass를 호출합니다.SleepOneSecond에서 오류가 발생하지 않습니다.나는 메인 라인에서 아래의 코드 MyClass를 시험해 보았다. = TMyClass.Create; MyClass.SleepOneSecond; MyClass.Free; MyClass.SleepOneSecond; 마찬가지로 오류가 발생하지는 않지만, 프로그램을 닫을 때 오류가 발생합니다. 만약 그렇다면: MyClass: = TMyClass.Create; MyClass.SleepOneSecond; MyClass.Free; MyThread := TMyThread.MyCreate(true); MyThread.OnTerminate := ThreadTerminate; MyThread.Resume; MyClass.SleepOneSecond; 금방 실수할 거야.그래서 이것은 라인 종류와 무선이므로 델피가 창고 공간에 대한 방출 규칙이어야 한다.
나는 MyClass를 원한다.Free 이후에도 객체는 스택에 남아 있으며 다른 리소스가 이 공간을 사용할 수 있도록 허용됩니다.
그래서 다음 MyClass를 이어서 호출합니다.SleepOneSecond는 오류가 발생하지 않습니다. 프로그램이 종료될 때 창고를 청소하는 중 오류가 발생할 수 있습니다.만약에 MyClass가Free 후에 MyThread를 만듭니다. 아마도 MyClass의 공간은 MyThread에서 사용되기 때문에 MyClass를 호출합니다.SleepOneSecond에서 오류가 발생했습니다.

좋은 웹페이지 즐겨찾기