destructor TAbstractTimerThread.Destroy; begin self.finalize; if FCheckEvent > 0 then CloseHandle(FCheckEvent);
if FActiveHandle > 0 then CloseHandle(FActiveHandle);
inherited; end;
procedure TAbstractTimerThread.Execute; var hResult: Cardinal; begin while not Terminated do begin //等待开始 WaitForSingleObject(FActiveHandle, INFINITE);
//中止线程时结束本次循环 if Self.Terminated then Break;
//等待时钟 //不是中止才执行工作函数 hResult := WaitForSingleObject(FCheckEvent, FCheckDelta); case hResult of WAIT_OBJECT_0: begin //空 end; WAIT_TIMEOUT: begin self.working; end; end;
end; end;
procedure TAbstractTimerThread.initialize; begin self.wake; end;
procedure TAbstractTimerThread.SetEnabled(const Value: Boolean); begin FEnabled := Value; if FEnabled then begin SetEvent(FActiveHandle); end else begin ResetEvent(FActiveHandle); end; end;
procedure TAbstractTimerThread.StopThread; begin self.Terminate; if not FEnabled then Self.Enabled := True;
workFinished; end;
procedure TAbstractTimerThread.wake; begin if self.Suspended then self.Resume;
if FEnabled then begin SetEvent(FActiveHandle); end else begin ResetEvent(FActiveHandle); end; end;
procedure TAbstractTimerThread.workFinished; begin SetEvent(FCheckEvent); end;
procedure TAbstractTimerThread.working; begin self.doWork; end;
destructor TimerEx.Destroy; begin if Assigned(FThreadTimer) then begin FThreadTimer.StopThread; FThreadTimer := nil; end; inherited; end;
function TimerEx.GetEnabled: Boolean; begin Result := False; if Assigned(FThreadTimer) then begin Result := FThreadTimer.Enabled;
end; end;
function TimerEx.GetInterval: Cardinal; begin Result := 1000; if Assigned(FThreadTimer) then begin Result := FThreadTimer.CheckDelta; end; end;
function TimerEx.GetPriority: TThreadPriority; begin Result := tpIdle; if Assigned(FThreadTimer) then Result := FThreadTimer.Priority; end;
procedure TimerEx.SetEnabled(value: Boolean); begin if Assigned(FThreadTimer) then FThreadTimer.Enabled := value; end;
procedure TimerEx.SetInterval(value: Cardinal); begin if Assigned(FThreadTimer) then FThreadTimer.CheckDelta := value; end;
procedure TimerEx.SetPriority(const Value: TThreadPriority); begin if Assigned(FThreadTimer) then FThreadTimer.Priority := value; end;
procedure TimerEx.ThreadTimerEvent(Sender: TObject); begin if self.ComponentState <> [csDesigning] then begin if Assigned(FOnTimer) then FOnTimer(self); end;
procedrure TMyThread.Execute; begin //假设这里有一些线程开始时的初始化代码,比如创建一些这个线程执行需要的对象的实例。 while True do begin if Self.Terminated then Break; //如果外面调用了线程的 Terminate 方法,实际上这个方法就是设置了线程的 Terminated 属性。而线程的结束,就是线程的死循环跳出来,线程执行到结尾,自然就结束。
the Thread basically should have a "point to controls" when STOP or not!
NOTE IMPORTANT:
NEVER RAISE AN EXCEPTION INTO THREADS!!! ELSE, YOUR APP WILL CRASH FOR SURE!
Using "TThread" class as base:
1) inherit from this class by default 2) override the "Execute" procedure ( at least) 3) put a "point of control" in each "part" sensible to stop it. 4) tests, tests, tests ....
ex.: NOTE: I use TEvent to controls too! but this code is enought for works!
in FormMain im just a variable or similar to say: STOP PLEASE! ... implementation
var MyThreadsWithEvent : TArray<TMyThreadWithEvent>; // MyThreadsStopAll :boolean = false;
...
procedure TViewFormMain.Btn_Thread_StopClick(Sender: TObject); begin MyThreadsStopAll := true; end;
constructor TMyThreadWithEvent.Create(AValue: integer; ASuspended: boolean = true); // <--- begin inherited Create(ASuspended); // YEAH, start suspended! ... wait my command!!! // FIndex := AValue; // OnTerminate := MyOnTerminate; FreeOnTerminate := false; // important in some situations!!! end;
procedure TMyThreadWithEvent.Execute; var FStatus: TWaitResult; begin // // ALWAYS TEST YOUR "POINT OF CONTROL" -> in my case, Im testing just here // while not(MyThreadsStopAll) do // <--- the magic is always observe it in "each" sensible task!!! begin if MyThreadsStopAll then break; // // FStatus := MyEventSharedWithAllThreads.WaitFor(MyEventTimeOutValue); // for my TEvent use // if MyThreadsStopAll then // <---- the magic!!! break; // (* my tests... TThread.Synchronize(nil, procedure begin if (Self.FIndex = 1) then ViewFormMain.LstBxThreadA.Items.Add(Self.ThreadID.MyText + ' -> ' + FStatus.MyText + ' ' + TimeToStr(now, MyFS)) else ViewFormMain.LstBxThreadB.Items.Add(Self.ThreadID.MyText + ' -> ' + FStatus.MyText + ' ' + TimeToStr(now, MyFS)); end); *) // sleep(1); // just for "provocate" a time on cpu... end; end;
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
procedure TimeP.Execute; begin while not Terminated do begin Sleep(1000); if formatdatetime('hh:mm:ss', now) = formatdatetime('hh:mm:ss', form1.DateTimePicker1.Time) then form1.Caption := TimetoStr(form1.DateTimePicker1.Time); end; end;