본문 바로가기
개발일지/아키텍트

Delphi 에서 Leader-Follower 패턴 구현

by 사악신 2012. 3. 14.

POSA2 에서 Leader-Follower 패턴의 경우 pthread 기반으로 구현하여 설명하고 있다.(

2012/03/09 - [프로그래밍/Lazarus] - FPC 에서 Leader-Follower 패턴 구현

) 이를 Windows 기반으로 작성해보았다.

unit DLNA.Thread;

interface

uses
  Winapi.Windows, System.SysUtils, SyncObjs;

const
  NO_CURRENT_LEADER = 0;

type
  TGuard = class
  protected
    FMutex: TMutex;
    FOwner: Boolean;
  public
    constructor Create(AMutex: TMutex);
    destructor Destroy; override;

    procedure Acquire;
    procedure Release;
  end;

  TThreadCondition = class
  protected
    FEvent: TEvent;
  public
    constructor Create;
    destructor Destroy; override;

    procedure Wait(Timeout: Cardinal);
    procedure Notify;
  end;

  // Unbound thread set
  TThreadSet = class
  protected
    FThreadLeader: Cardinal;
    FThreadCondition: TThreadCondition;
    FMutex: TMutex;
  public
    constructor Create;
    destructor Destroy; override;

    function Join(Timeout: Cardinal): Boolean; virtual;
    function PromoteNewLeader: Boolean; virtual;
  end;

implementation

{ TThreadSet }

constructor TThreadSet.Create;
begin
  inherited;

  FThreadLeader := NO_CURRENT_LEADER;
  FThreadCondition := TThreadCondition.Create;
  FMutex := TMutex.Create;
end;

destructor TThreadSet.Destroy;
begin
  FMutex.Free;
  FThreadCondition.Free;

  inherited;
end;

function TThreadSet.Join(Timeout: Cardinal): Boolean;
var
  Guard: TGuard;
begin
  Result := False;
  Guard := TGuard.Create(FMutex);
  OutputDebugString('Join 호출');
  try
    while FThreadLeader <> NO_CURRENT_LEADER do
    begin
      FThreadCondition.Wait(Timeout);
    end;

    FThreadLeader := GetCurrentThreadId;
    OutputDebugString(PWideChar('Thead Leader ID: '+IntToStr(FThreadLeader)));
    Guard.Release; // 다른 Follower Thread 가 Join 할 수 있게한다.
    Result := True;
  finally
    Guard.Free;
  end;
end;

function TThreadSet.PromoteNewLeader: Boolean;
var
  Guard: TGuard;
begin
  OutputDebugString('PromoteNewLeader 호출');
  Result := True;

  Guard := TGuard.Create(FMutex);
  try
    if FThreadLeader <> GetCurrentThreadId then Exit(False);
    FThreadLeader := NO_CURRENT_LEADER;
    FThreadCondition.Notify;
  finally
    Guard.Free;
  end;
end;

{ TGuard }

procedure TGuard.Acquire;
begin
  try
    FMutex.Acquire;
  except
    FOwner := True;
  end;
end;

constructor TGuard.Create(AMutex: TMutex);
begin
  inherited Create;

  if Assigned(AMutex) then
  begin
    FMutex := AMutex;
    try
      FMutex.Acquire;
    except
      FOwner := True;
    end;
  end;
end;

destructor TGuard.Destroy;
begin
  if FOwner then FMutex.Release;

  inherited;
end;

procedure TGuard.Release;
begin
  if FOwner then
  begin
    FMutex.Release;
    FOwner := False;
  end;
end;

{ TThreadCondition }

constructor TThreadCondition.Create;
begin
  inherited;

  FEvent := TEvent.Create;
  FEvent.ResetEvent; // TEvent.ResetEvent - turn off
end;

destructor TThreadCondition.Destroy;
begin
  FEvent.Free;

  inherited;
end;

procedure TThreadCondition.Notify;
begin
  FEvent.SetEvent; // TEvent.SetEvent - turn on
end;

procedure TThreadCondition.Wait(Timeout: Cardinal);
begin
  // TEvent.WaitFor - SetEvent 가 호출될때까지 대기함
  // wrSignaled, wrTimeout, wrAbandoned, wrError
  FEvent.WaitFor(Timeout);
end;

end.

IOCP 기반 스레드풀 구현시 사용해보았는데 현재까지 큰 문제는 없어보인다. 하지만, 아직은 초기적인 구조라고 말할 수 있겠다.

반응형

'개발일지 > 아키텍트' 카테고리의 다른 글

POSA2, Scoped Locking, Strategized Locking 패턴  (0) 2012.04.05
Proactor with EPOLL, SELECT  (2) 2012.03.15
FPC 에서 Leader-Follower 패턴 구현  (0) 2012.03.09
POSA, 패턴 시스템  (0) 2012.02.14
Proactor with IOCP  (4) 2012.02.13

댓글