unit Threading; interface uses System.SysUtils, System.Classes; type TThreadStatus = (tsReady, tsRunning, tsErrored, tsTerminated); EThreadException = class(Exception); TTask = class(TThread) private FSync: Boolean; FErrorMsg: string; FStatus: TThreadStatus; FProc0: TProc; FProc1: TProc; FProc2: TProc; FProc3: TProc; FProc4: TProc; FArgs: array [0 .. 3] of IntPtr; FStarted: Boolean; public constructor Create(Arg1: IntPtr = 0; Arg2: IntPtr = 0; Arg3: IntPtr = 0; Arg4: IntPtr = 0); destructor Destroy; override; procedure Update(Arg1: IntPtr = 0; Arg2: IntPtr = 0; Arg3: IntPtr = 0; Arg4: IntPtr = 0); procedure Perform(const Proc: TProc); overload; procedure Perform(const Proc: TProc); overload; procedure Perform(const Proc: TProc); overload; procedure Perform(const Proc: TProc); overload; procedure Perform(const Proc: TProc); overload; procedure Execute; override; procedure Start; procedure Wait; procedure RaiseLastError; property Status: TThreadStatus read FStatus; property Sync: Boolean read FSync write FSync; end; procedure WaitForAll(const Tasks: array of TTask); function WaitForAny(const Tasks: array of TTask): Integer; function IsErrored(const Tasks: array of TTask): Boolean; implementation constructor TTask.Create(Arg1, Arg2, Arg3, Arg4: IntPtr); begin inherited Create(True); FSync := False; FErrorMsg := ''; FStatus := tsReady; FProc0 := nil; FProc1 := nil; FProc2 := nil; FProc3 := nil; FProc4 := nil; FArgs[0] := Arg1; FArgs[1] := Arg2; FArgs[2] := Arg3; FArgs[3] := Arg4; FStarted := False; end; destructor TTask.Destroy; begin FStatus := tsTerminated; inherited Destroy; end; procedure TTask.Update(Arg1, Arg2, Arg3, Arg4: IntPtr); begin FArgs[0] := Arg1; FArgs[1] := Arg2; FArgs[2] := Arg3; FArgs[3] := Arg4; end; procedure TTask.Perform(const Proc: TProc); begin FProc0 := Proc; FProc1 := nil; FProc2 := nil; FProc3 := nil; FProc4 := nil; end; procedure TTask.Perform(const Proc: TProc); begin FProc0 := nil; FProc1 := Proc; FProc2 := nil; FProc3 := nil; FProc4 := nil; end; procedure TTask.Perform(const Proc: TProc); begin FProc0 := nil; FProc1 := nil; FProc2 := Proc; FProc3 := nil; FProc4 := nil; end; procedure TTask.Perform(const Proc: TProc); begin FProc0 := nil; FProc1 := nil; FProc2 := nil; FProc3 := Proc; FProc4 := nil; end; procedure TTask.Perform(const Proc: TProc); begin FProc0 := nil; FProc1 := nil; FProc2 := nil; FProc3 := nil; FProc4 := Proc; end; procedure TTask.Execute; label Restart; begin Restart: while FStatus in [tsReady, tsErrored] do Sleep(1); try if FStatus = tsRunning then begin if Assigned(FProc0) or Assigned(FProc1) or Assigned(FProc2) or Assigned(FProc3) or Assigned(FProc4) then begin if FSync then Self.Synchronize( procedure begin if Assigned(FProc0) then FProc0 else if Assigned(FProc1) then FProc1(FArgs[0]) else if Assigned(FProc2) then FProc2(FArgs[0], FArgs[1]) else if Assigned(FProc3) then FProc3(FArgs[0], FArgs[1], FArgs[2]) else if Assigned(FProc4) then FProc4(FArgs[0], FArgs[1], FArgs[2], FArgs[3]); end) else begin if Assigned(FProc0) then FProc0 else if Assigned(FProc1) then FProc1(FArgs[0]) else if Assigned(FProc2) then FProc2(FArgs[0], FArgs[1]) else if Assigned(FProc3) then FProc3(FArgs[0], FArgs[1], FArgs[2]) else if Assigned(FProc4) then FProc4(FArgs[0], FArgs[1], FArgs[2], FArgs[3]); end; end; FStatus := tsReady; end; except on E: Exception do begin if E.Message <> '' then FErrorMsg := E.Message else FErrorMsg := 'Unknown error'; FStatus := tsErrored; end; end; if FStatus <> tsTerminated then goto Restart; end; procedure TTask.Start; begin if not FStarted then begin FStarted := True; inherited Start; end; FStatus := tsRunning; end; procedure TTask.Wait; begin while FStatus = tsRunning do Sleep(1); end; procedure TTask.RaiseLastError; begin if FErrorMsg <> '' then begin raise EThreadException.Create(FErrorMsg); FErrorMsg := ''; end; end; procedure WaitForAll(const Tasks: array of TTask); var I: Integer; begin for I := Low(Tasks) to High(Tasks) do Tasks[I].Wait; end; function WaitForAny(const Tasks: array of TTask): Integer; var I: Integer; begin while True do begin for I := Low(Tasks) to High(Tasks) do begin if Tasks[I].Status <> tsRunning then begin Result := I; exit; end; end; Sleep(1); end; end; function IsErrored(const Tasks: array of TTask): Boolean; var I: Integer; begin Result := False; for I := Low(Tasks) to High(Tasks) do begin if Tasks[I].Status = TThreadStatus.tsErrored then begin Result := True; exit; end; end; end; end.