Multithreading with TThread

28.1 Subclassing TThread

type
  TWorker = class(TThread)
  private
    FProgress: Integer;
    procedure UpdateUI;
  protected
    procedure Execute; override;
  public
    constructor Create;
  end;

constructor TWorker.Create;
begin
  inherited Create(True);          // create suspended
  FreeOnTerminate := True;         // frees itself when done (then don't keep or touch the reference!)
end;

procedure TWorker.Execute;
begin
  NameThreadForDebugging('Worker');
  for var I := 1 to 100 do
  begin
    if Terminated then Exit;       // cooperative cancellation
    Sleep(50);                     // simulate work
    FProgress := I;
    Synchronize(UpdateUI);         // run on the main thread (blocking)
    // or Queue(UpdateUI);          // non-blocking
  end;
end;

procedure TWorker.UpdateUI;
begin
  MainForm.ProgressBar1.Position := FProgress;
end;

// Start
var W := TWorker.Create;
W.Start;

28.2 Anonymous Threads

TThread.CreateAnonymousThread(
  procedure
  begin
    var Data := LoadDataFromServer;           // background work
    TThread.Queue(nil,
      procedure
      begin
        Memo1.Lines.Text := Data;            // safely update the UI on the main thread
      end);
  end).Start;

28.3 Thread Rules

Never touch VCL/FMX controls from a background thread. Use Synchronize/Queue (or TThread.ForceQueue).

Thread lifecycle: Create(Suspended), Start, Terminate (sets the flag), WaitFor, FreeOnTerminate, OnTerminate event (runs in the main thread), Priority, ThreadID, TThread.CurrentThread, TThread.Sleep, TThread.Yield.

Thread-local variables: threadvar Counter: Integer;.