Skip to content

Commit 9b65e34

Browse files
committed
ThreadPythonExec wrapper around TPythonThread added.
1 parent f9be506 commit 9b65e34

File tree

1 file changed

+81
-0
lines changed

1 file changed

+81
-0
lines changed

Source/PythonEngine.pas

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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
29342936
function 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+
98619942
end.
98629943

0 commit comments

Comments
 (0)