본문 바로가기
Delphi/클래스

멀티스레드 GUI 동기화

by MonoSoft 2022. 1. 14.
728x90
반응형

멀티스레드 GUI 동기화

 

일반적인 Delphi 애플리케이션은 단일 스레드이므로

모든 VCL 객체가 속성에 액세스하고이 단일 스레드 내에서 메서드를 실행합니다.

 

애플리케이션에서 데이터 처리 속도를 높이려면 하나 이상의

보조 스레드를 포함하십시오.

 

프로세서 스레드

스레드 프로세서에 응용 프로그램의 통신 채널이다.

단일 스레드 프로그램은 실행시 양방향으로 (프로세서에서) 양방향으로 통신해야합니다.

다중 스레드 앱은 여러 채널을 열 수 있으므로 실행 속도가 빨라집니다.

 

스레드 및 GUI

애플리케이션에서 여러 스레드가 실행 중일 때 스레드 실행의 결과로

그래픽 사용자 인터페이스를 업데이트 할 수있는 방법에 대한 의문이 생깁니다.

대답은 TThread 클래스 Synchronize 메서드에 있습니다.

 

보조 스레드에서 애플리케이션의 사용자 인터페이스 또는 기본 스레드를 업데이트하려면

Synchronize 메서드를 호출해야합니다.

이 기술은 스레드로부터 안전하지 않은 개체 속성 또는

메서드에 액세스하거나 기본 실행 스레드에없는 리소스를 사용하여

발생할 수있는 다중 스레딩 충돌을 방지하는 스레드로부터 안전한 방법입니다.

 

아래는 진행률 표시 줄이있는 여러 버튼을 사용하는 예제 소스와 샘풀프로그램입니다.

각 진행률 표시 줄은 스레드 실행의 현재 "상태"를 표시합니다.

 

unit MainU;

 

 interface

 

 uses

   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

   Dialogs, ComCtrls, StdCtrls, ExtCtrls;

 

 type

   //interceptor class

   TButton = class(StdCtrls.TButton)

     OwnedThread: TThread;

     ProgressBar: TProgressBar;

   end;

 

   TMyThread = class(TThread)

   private

     FCounter: Integer;

     FCountTo: Integer;

     FProgressBar: TProgressBar;

     FOwnerButton: TButton;

 

     procedure DoProgress;

     procedure SetCountTo(const Value: Integer) ;

     procedure SetProgressBar(const Value: TProgressBar) ;

     procedure SetOwnerButton(const Value: TButton) ;

   protected

     procedure Execute; override;

   public

     constructor Create(CreateSuspended: Boolean) ;

     property CountTo: Integer read FCountTo write SetCountTo;

     property ProgressBar: TProgressBar read FProgressBar write SetProgressBar;

     property OwnerButton: TButton read FOwnerButton write SetOwnerButton;

   end;

 
   TMainForm = class(TForm)

     Button1: TButton;

     ProgressBar1: TProgressBar;

     Button2: TButton;

     ProgressBar2: TProgressBar;

     Button3: TButton;

     ProgressBar3: TProgressBar;

     Button4: TButton;

     ProgressBar4: TProgressBar;

     Button5: TButton;

     ProgressBar5: TProgressBar;

     procedure Button1Click(Sender: TObject) ;

   end;

 

 var

   MainForm: TMainForm;

 

 implementation

 

 {$R *.dfm}

 

 { TMyThread }

 

 constructor TMyThread.Create(CreateSuspended: Boolean) ;

 begin

   inherited;

   FCounter := 0;

   FCountTo := MAXINT;

 end;

 

 procedure TMyThread.DoProgress;

 var

   PctDone: Extended;

 begin

   PctDone := (FCounter / FCountTo) ;

   FProgressBar.Position := Round(FProgressBar.Step * PctDone) ;

   FOwnerButton.Caption := FormatFloat('0.00 %', PctDone * 100) ;

 end;

 

 procedure TMyThread.Execute;

 const

   Interval = 1000000;

 begin

   FreeOnTerminate := True;

   FProgressBar.Max := FCountTo div Interval;

   FProgressBar.Step := FProgressBar.Max;

 

   while FCounter < FCountTo do

   begin

     if FCounter mod Interval = 0 then Synchronize(DoProgress) ;

     Inc(FCounter) ;

   end;

 

   FOwnerButton.Caption := 'Start';

   FOwnerButton.OwnedThread := nil;

   FProgressBar.Position := FProgressBar.Max;

 end;

 

 procedure TMyThread.SetCountTo(const Value: Integer) ;

 begin

   FCountTo := Value;

 end;

 

 procedure TMyThread.SetOwnerButton(const Value: TButton) ;

 begin

   FOwnerButton := Value;

 end;

 

 procedure TMyThread.SetProgressBar(const Value: TProgressBar) ;

 begin

   FProgressBar := Value;

 end;

 

 procedure TMainForm.Button1Click(Sender: TObject) ;

 var

   aButton: TButton;

   aThread: TMyThread;

   aProgressBar: TProgressBar;

 begin

   aButton := TButton(Sender) ;

   if not Assigned(aButton.OwnedThread) then

   begin

     aThread := TMyThread.Create(True) ;

     aButton.OwnedThread := aThread;

     aProgressBar := TProgressBar(FindComponent(StringReplace(aButton.Name, 'Button', 'ProgressBar', []))) ;

     aThread.ProgressBar := aProgressBar;

     aThread.OwnerButton := aButton;

     aThread.Resume;

     aButton.Caption := 'Pause';

   end

   else

   begin

     if aButton.OwnedThread.Suspended then

       aButton.OwnedThread.Resume

     else

       aButton.OwnedThread.Suspend;

 

     aButton.Caption := 'Run';

   end;

 end;

 end.

 

멀티프로그레스바.zip
3.28MB

728x90
반응형

댓글