unit SimpleThread;

interface

uses
  ThreadPool,
  Windows, Classes, SysUtils;

type
  {*
    A Simple thread class that can change stack size for it.
  }
  TSimpleThread = class
  private
    FHandle: THandle platform;
    FThreadID : TThreadID;
    FIsRunning : boolean;
    FTerminated : boolean;
    FFreeOnTerminate: Boolean;
    FOnExecute: TNotifyEvent;
    procedure init;
    procedure do_Execute;
  protected
    FEventHandle: THandle;
    procedure BeginSimpleThread(AStackSize: integer); virtual;
    procedure Execute; virtual;
  public
    class var StackSize : integer;

    constructor Create; overload;
    constructor Create(AStackSize:integer); overload;
    constructor Create(AEventHandle:TNotifyEvent); overload;
    constructor Create(AStackSize:integer; AEventHandle:TNotifyEvent); overload;

    procedure Terminate; overload;
    procedure Terminate(ATimeout:integer); overload;

    procedure SleepTight;
    procedure WakeUp;

    property Handle : THandle read FHandle;
    property ThreadID : TThreadID read FThreadID;
    property FreeOnTerminate: Boolean read FFreeOnTerminate write FFreeOnTerminate;
    property Terminated : boolean read FTerminated;
  end;

implementation

{ TSimpleThread }

function SimpleThreadProc(Parameter : Pointer) : Integer;
begin
  Result := 0;
  try
    TSimpleThread(Parameter).do_Execute;
  finally
    EndThread(0);
    if TSimpleThread(Parameter).FFreeOnTerminate then TSimpleThread(Parameter).Free;
  end;
end;

procedure TSimpleThread.BeginSimpleThread(AStackSize: integer);
begin
  FHandle := BeginThread(nil, StackSize, @SimpleThreadProc, Pointer(Self), 0, FThreadID);
end;

constructor TSimpleThread.Create;
begin
  inherited;

  init;
  BeginSimpleThread(StackSize);
end;

constructor TSimpleThread.Create(AStackSize: integer);
begin
  init;
  BeginSimpleThread(AStackSize);
end;

constructor TSimpleThread.Create(AEventHandle: TNotifyEvent);
begin
  FOnExecute := AEventHandle;
  init;
  BeginSimpleThread(StackSize);
end;

constructor TSimpleThread.Create(AStackSize: integer;
  AEventHandle: TNotifyEvent);
begin
  FOnExecute := AEventHandle;
  init;
  BeginSimpleThread(AStackSize);
end;

procedure TSimpleThread.do_Execute;
begin
  try
    Execute;
  except
    Terminate;
  end;

  FIsRunning := false;
end;

procedure TSimpleThread.Execute;
begin
  if Assigned(FOnExecute) then FOnExecute(Self);
end;

procedure TSimpleThread.init;
begin
  FFreeOnTerminate := true;
  FTerminated := false;
  FIsRunning := true;

  FEventHandle := CreateEvent(nil, false, false, nil);
end;

procedure TSimpleThread.SleepTight;
begin
  if not FTerminated then WaitforSingleObject(FEventHandle, INFINITE);
end;

procedure TSimpleThread.Terminate;
begin
  FTerminated := true;
end;

function TerminateThread(lpThreadParameter: Pointer): Integer; stdcall;
begin
  if lpThreadParameter <> nil then
    TSimpleThread(lpThreadParameter).Terminate;

  Result := 0;
end;

procedure TSimpleThread.Terminate(ATimeout: integer);
begin
  QueueWorkItem(TerminateThread, Self);

  if (FIsRunning) and (ATimeout > 0) then WaitforSingleObject(FHandle, ATimeout);
end;

procedure TSimpleThread.WakeUp;
begin
  SetEvent(FEventHandle);
end;

{ TSleepyThread }

function SleepyThreadProc(Parameter : Pointer) : Integer;
begin
  Result := 0;
  try
    TSimpleThread(Parameter).do_Execute;
  finally
    EndThread(0);
    if TSimpleThread(Parameter).FFreeOnTerminate then TSimpleThread(Parameter).Free;
  end;
end;

initialization
  TSimpleThread.StackSize := 32 * 1024;
end.
