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 |
댓글