@@ -2931,8 +2931,18 @@ function PyStatus_Exception(const APyStatus: PyStatus): Boolean;
29312931 end ;
29322932
29332933//  Access the PythonEngine with thread safety
2934+ 
2935+ //  Gets the GIL and releases it automatically when the interface is cleared
29342936function  SafePyEngine : IPyEngineAndGIL;
29352937
2938+ { $IFNDEF FPC} 
2939+ { 
2940+  Executes Python code in a Delphi thread - Wrapper around TPythonThread 
2941+  The TerminateProc is called using TThread.Queue 
2942+ } 
2943+ procedure  ThreadPythonExec (ExecuteProc : TProc; TerminateProc : TProc = nil ;
2944+  WaitToFinish: Boolean = False; ThreadExecMode : TThreadExecMode = emNewState);
2945+ { $ENDIF FPC} 
29362946
29372947{  Helper functions} 
29382948
@@ -9858,5 +9868,76 @@ function SafePyEngine: IPyEngineAndGIL;
98589868
98599869
98609870
9871+ { $IFNDEF FPC} 
9872+ 
9873+ {  TAnonymousPythonThread } 
9874+ 
9875+ type 
9876+  TAnonymousPythonThread = class (TPythonThread)
9877+  private 
9878+  fTerminateProc : TProc;
9879+  fExecuteProc : TProc;
9880+  procedure  DoTerminate ; override;
9881+  public 
9882+  procedure  ExecuteWithPython ; override;
9883+  constructor  Create(ExecuteProc : TProc; TerminateProc : TProc = nil ;
9884+  Suspended: Boolean = False; AThreadExecMode : TThreadExecMode = emNewState);
9885+  end ;
9886+ 
9887+ constructor  TAnonymousPythonThread.Create(ExecuteProc : TProc; TerminateProc : TProc;
9888+  Suspended: Boolean; AThreadExecMode : TThreadExecMode);
9889+ begin 
9890+  inherited  Create(Suspended);
9891+  fExecuteProc := ExecuteProc;
9892+  fTerminateProc := TerminateProc;
9893+  FreeOnTerminate := True;
9894+  ThreadExecMode := AThreadExecMode;
9895+ end ;
9896+ 
9897+ procedure  TAnonymousPythonThread.ExecuteWithPython ;
9898+ begin 
9899+  if  Assigned(fExecuteProc) then 
9900+  try 
9901+  fExecuteProc();
9902+  except 
9903+  end ;
9904+ end ;
9905+ 
9906+ procedure  TAnonymousPythonThread.DoTerminate ;
9907+ //  Use Thread.Queue to run the TerminateProc in the main thread
9908+ //  Could use Synchronize instead, but such calls better be avoided
9909+ var 
9910+  TerminateProc: TProc;
9911+ begin 
9912+  TerminateProc := fTerminateProc; //  to keep fTerminateProc alive at destruction
9913+  if  Assigned(TerminateProc) then 
9914+  TThread.Queue(nil , procedure
9915+  begin 
9916+  TerminateProc();
9917+  end );
9918+ end ;
9919+ 
9920+ 
9921+ {  InternalThreadPythonExec } 
9922+ 
9923+ procedure  ThreadPythonExec (ExecuteProc : TProc; TerminateProc : TProc;
9924+  WaitToFinish: Boolean; ThreadExecMode : TThreadExecMode);
9925+ var 
9926+  Thread: TAnonymousPythonThread;
9927+ begin 
9928+  if  GetCurrentThreadId <> MainThreadID then 
9929+  raise Exception.Create(' ThreadPythonExec should only be called from the main thread'  );
9930+  Thread := TAnonymousPythonThread.Create(ExecuteProc, TerminateProc, WaitToFinish, ThreadExecMode);
9931+  if  WaitToFinish then 
9932+  begin 
9933+  Thread.FreeOnTerminate := False;
9934+  Thread.Start;
9935+  Thread.WaitFor; //  Note that it calls CheckSyncrhonize
9936+  Thread.Free;
9937+  end ;
9938+ end ;
9939+ 
9940+ { $ENDIF FPC} 
9941+ 
98619942end .
98629943
0 commit comments