본문 바로가기
Delphi, RadStudio

[개발/delphi] Thread 사용 예제

by SB리치퍼슨 2012. 9. 4.


Thread 사용 예제.... 몇가지 유의할 점들을 기억해두자.
기본적인 내용들이지만 잊어버리고 에러를 만들어내는 우리들 개발자들이다.... 항상 되새김질을하자.

출처: 인터넷


//

// Thread class 정의 예제

//

unit RainbowThread;

interface

uses

  Classes, SysUtils, ExtCtrls;

type

  TRainbowThread = class(TThread)

  private

    { Private declarations }

    FShape : TShape;

  protected

    procedure Execute; override;

  public

    Constructor Create(Shape:TShape);

  end;

implementation

{ TRainbowThread }

procedure TRainbowThread.Execute;

begin

  Repeat

    FShape.Brush.Color:=

      Round(Random(256)) shl 16 +

      Round(Random(256)) shl  8 +

      Round(Random(256));

    Sleep(200);

  Until Terminated = True;  //=====> Terminated 변수의 검사로 진행여부를 결정하도록 처리 한다

end;

Constructor TRainbowThread.Create(Shape:TShape);

Begin

  FShape:= Shape;  //=====> 초기화 처리는 Inherited Create() 함수 보다 먼저 기입 한다

  Inherited Create(True);

End;

end.

 

 

//--------------------------------------------------//

// 사용법 1                                         

//--------------------------------------------------//

  // 생성 부분

  // 전달인자가 True 일때는 Resume 호출로 실행 시켜야 한다

  Thread1:= Thread.Create( True ); 

  // 재개

  Thread1.Resume;   

  // 일시 중지

  Thread1.Suspend;  

  // 실행 종료

  Thread1.Terminate;

  // 실행 종료 대기

  Thread1.WaitFor;

  // 제거 부분

  Thread1.Free;  // 또는 FreeAndNil( Thread1 );

  --< 주의 >-----------------------------------------

  Resume 을 호출하지 않은 상태에서

  Suspend를 호출하면 프로그램에 문제가 생겨서 

  프로그램이 정지 한다


//--------------------------------------------------//

// 사용법 2                                         

//--------------------------------------------------//

  // 생성 부분

  // 전달인자가 False 이면 바로 실행 한다

  // 전달인자가 False 일때 Suspend 함수를 호출하면

  // 프로그램에 문제가 생겨서 프로그램이 정지 한다

  Thread1:= Thread.Create( False );

  // 제거 부분

  Thread1.Free;  // 또는 FreeAndNil( Thread1 );


//--------------------------------------------------//

// 사용법 3                                         

//--------------------------------------------------//

  // 생성 부분

  // 전달인자는 실행 시작 여부

  // True  = Resume 함수 호출로 시작

  // False = 바로 시작

  Thread1:= Thread.Create( True ); 

  // 실행 종료 되면 자동 제거

  Thread1.FreeOnTerminate := True;

  // 실행 종료

  Thread1.Terminate;


// --< 주의 >---------------------------------------------

//  FreeOnTerminate := True; 로 지정한 후에는

//  Suspend 또는 Free 함수를 호출하면

//  프로그램에 문제가 생겨서 프로그램이 정지 한다




Delphi Multithreading

When you need to perform background operations or any processing not strictly related to the user interface, you can follow the technically most correct approach: spawn a separate thread of execution within the process. Multithreading programming might seem like an obscure topic, but it really isn't that complex, even if you must consider it with care. It is worth knowing at least the basics of multithreading, because in the world of sockets and Internet programming, there is little you can do without threads.

Delphi's RTL library provides a TThread class that will let you create and control threads. You will never use the TThread class directly, because it is an abstract class—a class with a virtual abstract method. To use threads, you always subclass TThread and use the features of this base class.

The TThread class has a constructor with a single parameter (CreateSuspended) that lets you choose whether to start the thread immediately or suspend it until later. If the thread object starts automatically, or when it is resumed, it will run its Execute method until it is done. The class provides a protected interface, which includes the two key methods for your thread subclasses:

procedure Execute; virtual; abstract;
procedure Synchronize(Method: TThreadMethod);

The Execute method, declared as a virtual abstract procedure, must be redefined by each thread class. It contains the thread's main code—the code you would typically place in a thread function when using the system functions.

The Synchronize method is used to avoid concurrent access to VCL components. The VCL code runs inside the program's main thread, and you need to synchronize access to VCL to avoid re-entry problems (errors from re-entering a function before a previous call is completed) and concurrent access to shared resources. The only parameter of Synchronize is a method that accepts no parameters, typically a method of the same thread class. Because you cannot pass parameters to this method, it is common to save some values within the data of the thread object in the Execute method and use those values in the synchronized methods.

Note 

Delphi 7 includes two new versions of Synchronize that allow you to synchronize a method with the main thread without calling it from the thread object. Both the new overloaded Synchronize andStaticSynchronize are class methods of TThread and require a thread as parameter.

Another way to avoid conflicts is to use the synchronization techniques offered by the operating system. The SyncObjs unit defines a few VCL classes for some of these low-level synchronization objects, such as events (with the TEvent class and the TSingleEvent class) and critical sections (with the TCriticalSection class). (Synchronization events should not be confused with Delphi events, as the two concepts are unrelated.)

An Example of Threading

For an example of a thread, you can refer again to the BackTask example. This example spawns a secondary thread for computing the sum of the prime numbers. The thread class has the typical Executemethod, an initial value passed in a public property (Max), and two internal values (FTotal and FPosition) used to synchronize the output in the ShowTotal and UpdateProgress methods. The following is the complete class declaration for the custom thread object:

type
  TPrimeAdder = class(TThread)
  private
    FMax, FTotal, FPosition: Integer;
  protected
    procedure Execute; override;
    procedure ShowTotal;
    procedure UpdateProgress;
  public
    property Max: Integer read FMax write FMax;
  end;

The Execute method is very similar to the code used for the buttons in the BackTask example listed earlier. The only difference is in the final call to Synchronize, as you can see in the following two fragments:

procedure TPrimeAdder.Execute;
var
  I, Tot: Integer;
begin
  Tot := 0;
  for I := 1 to FMax do
  begin
    if IsPrime (I) then
      Tot := Tot + I;
    if I mod (fMax div 100) = 0 then
    begin
      FPosition := I * 100 div fMax;
      Synchronize(UpdateProgress);
    end;
  FTotal := Tot;
  Synchronize(ShowTotal);
end;
   
procedure TPrimeAdder.ShowTotal;
begin
  ShowMessage ('Thread: ' + IntToStr (FTotal));
end;
   
procedure TPrimeAdder.UpdateProgress;
begin
  Form1.ProgressBar1.Position := fPosition;
end;

The thread object is created when a button is clicked and is automatically destroyed as soon as its Execute method is completed:

procedure TForm1.Button3Click(Sender: TObject);
var
  AdderThread: TPrimeAdder;
begin
  AdderThread := TPrimeAdder.Create (True);
  AdderThread.Max := Max;
  AdderThread.FreeOnTerminate := True;
  AdderThread.Resume;
end;

반응형

댓글