.....

function CheckSynchronized(Timeout: Integer = 0): Boolean;
var
ticks: DWORD;

  procedure YieldTo;
  var
    ticksnew: DWORD;
  begin
    if Assigned(OnCheckSynchronize) then
    begin
      ticksnew := GetTicksDurate(ticks);
      if ticksNew > CheckSynchronizeTimeout then
      begin
        OnCheckSynchronize(nil);
        ticks := GetTickCount;
      end;
    end;
  end;

var
  SyncNode: TSyncNode;
begin
  // we only call this method from the mainthread
  if GetCurrentThreadID <> MainThreadID then
    raise EThread.CreateResFmt(@SCheckSynchronizeError, [GetCurrentThreadID]);

  if (Timeout = 0) or ThreadsSyncEvent.Signaled(Timeout) then
    ThreadsSyncEvent.ResetEvent;

  ticks := GetTickCount;
  SyncNode := SyncList.Pop;
  Result := SyncNode <> nil;
  if Result then
    while SyncNode <> nil do
    begin
      SyncNode.Run;
      YieldTo;
      SyncNode := SyncList.Pop;
      if SyncNode <> nil then
        ThreadsSyncEvent.SetEvent;
    end
    else
      YieldTo;
end;

procedure TExThread.DoAfterProcess;
begin
  FOnAfterProcessOK(Self);
end;

procedure TExThread.DoIdle;
begin
  Inc(FResponsiveness);
  Status := THREAD_STATE_PROCESS; // being Idle is sort of processing anyway
end;

procedure TExThread.AfterProcess;
begin
end
;

procedure TExThread.BeforeProcess;
begin
  Inc(FResponsiveness);
end;

function TExThread.ProcessWait(ResWait: DWORD): Boolean;
begin
  Result := True;
  if ResWait = WAIT_OBJECT_0 + WaitHandlesCount then // input available
    ProcessMessages // process the new input
  else
    if ResWait = WAIT_TIMEOUT then // wait timeout
      DoIdle
    else
      Result := False; // this includes:
  // WAIT_OBJECT_0 --> Thread Event
  // WAIT_OBJECT_0 + 1 --> shut down Application event
  // WAIT_ABANDONED_0..n --> an abandoned mutex, but won't happen in my code
  // WAIT_IO_COMPLETION --> queued APC
end;

procedure TExThread.Execute;
begin
  if Terminated then Exit;
  {$IFDEF ATLEAST_D14}
 
NameThreadForDebugging(FriendlyName);
  {$ELSE}
 
if bIsDebuggerPresent then SetName;
  {$ENDIF}
 
StartExec;
  try
    if not Terminated then
    begin
      repeat
        (* When tasking, TExThread basically loops calling Process (which descendants override)
        every FTaskSlice for a total durate of FDurate, checking for termination between loops.
        Between loops, the thread sleeps calling SleepUI.*)
 

        if FUseTask then Task
        else

        (* When not tasking and using wait message calls, the thread sets up an array of wait objects
        and sits waiting for at least one of them to be signaled. Always the first handle in the array
        is the thread handle. Always the second object in the array is the application shut down event
        handle. Your code must always process these two handles first, then other handles you may want
        to add to the array (wait for file notification, printer notification, etc and lastly
        call inherited ProcessWait to process errors, timeouts, abandons...*)

        if
FUseWaitMsg then
        repeat
          Status := THREAD_STATE_SUSPENDED;
          if FAlertableWait then
            ProcessWait(MsgWaitForMultipleObjectsEx(WaitHandlesCount, WaitHandles[0],
                        FTaskSlice, QS_SENDMESSAGE, 0))
          else
            ProcessWait(MsgWaitForMultipleObjects(WaitHandlesCount, WaitHandles[0],
                        False, FTaskSlice, QS_SENDMESSAGE))
        until Terminated

        (* When not tasking, nor waiting for events, we call straight Process which descendants
        override as needed. We can still loop Process calls, this time by using the flag FCanCycleExec.
        "Process" calls are wrapped between 2 other methods: BeforeProcess and AfterProcess.*)

        else
        begin

          BeforeProcess; // guaranteed to execute once per Process calls
          Process;
          AfterProcess; // not guaranteed to be executed
        end;

      until Terminated or not FCanCycleExec;

      if Assigned(FOnAfterProcessOK) then
        if FSynchAfterProcess then
          Synchronize(DoAfterProcess)
        else
          DoAfterProcess;
    end;
  finally
    EndExec;
  end;
end;

procedure TExThread.Task;

  procedure Perform(Data: Pointer; var NewSlice: DWORD; var Done: Boolean);
  begin
    Process(NewSlice, Done);
  end;

begin
  if not Terminated then
    LoopTask(@Perform,   // repeat Perform
             FTaskSlice, // every FTaskSlice
             FDurate,    // for a total of FDurate
             TRUE);      // check for termination between loops
end;