unit untThread;

interface

uses
  Classes, SysUtils;

type
  TISCThreadMethod<D, T> = function (ATID: TThreadID; AData: D): T of object;
  TISCTerminateMethod<T> = procedure (ATID: TThreadID; AData: T) of object;

  TInnerThread<D, T> = class(TThread)
  private
    FData: D;
    FOutData: T;
    FExecMethod: TISCThreadMethod<D, T>;
    FOutMethod: TISCTerminateMethod<T>;
    procedure innerTerminate(Sender: TObject);
  protected
    procedure Execute; override;
  public
    constructor Create(InnerData: D; AMethod: TISCThreadMethod<D, T>; ATermMethod: TISCTerminateMethod<T>);
  end;

type
  ThreadEXT = class
  public
    class function ThreadExecute<E, U>(AData: E; AMethod: TISCThreadMethod<E, U>; AOnTerminate: TISCTerminateMethod<U> = nil): TThread;
  end;

implementation

class function ThreadEXT.ThreadExecute<E, U>(AData: E; AMethod: TISCThreadMethod<E, U>; AOnTerminate: TISCTerminateMethod<U> = nil): TThread;
var
  th: TInnerThread<E, U>;
begin
  th := TInnerThread<E, U>.Create(AData, AMethod, AOnTerminate);
  th.Start();
  Exit(th);
end;

{ TInnerThread<D, T> }

constructor TInnerThread<D, T>.Create(InnerData: D;
  AMethod: TISCThreadMethod<D, T>; ATermMethod: TISCTerminateMethod<T>);
begin
  inherited Create(True);
  FreeOnTerminate:= True;
  OnTerminate:= innerTerminate;
  FData:= InnerData;
  FExecMethod:= AMethod;
  FOutMethod:= ATermMethod;
end;

procedure TInnerThread<D, T>.Execute;
begin
  FOutData:= FExecMethod(ThreadID, FData);
end;

procedure TInnerThread<D, T>.innerTerminate(Sender: TObject);
begin
  if (Assigned(FOutMethod)) then begin
    FOutMethod(ThreadID, FOutData);
  end;
end;

end.
