TaskManager refactoring
This commit is contained in:
+16
-48
@@ -11,37 +11,22 @@ uses
|
||||
Myc.Signals;
|
||||
|
||||
type
|
||||
IMycThreadPool = interface(TTaskManager.IMycTaskManager)
|
||||
IThreadPool = interface(TTaskManager.ITaskManager)
|
||||
{$region 'property access'}
|
||||
// Retrieves the number of worker threads.
|
||||
function GetThreadCount: Integer;
|
||||
{$endregion}
|
||||
|
||||
// Creates and starts a new, independent thread executing Proc.
|
||||
// Returns IMycState to await thread completion.
|
||||
// Exceptions within Proc are caught; the first one is stored
|
||||
// and can be re-raised in the main thread via WaitFor or Teardown.
|
||||
function CreateThread(const Proc: TProc): TState.IState;
|
||||
|
||||
// Returns True if called from the main application thread.
|
||||
function InMainThread: Boolean;
|
||||
|
||||
// Returns True if called from one of the factory's worker threads.
|
||||
function InWorkerThread: Boolean;
|
||||
|
||||
// Schedules Job for execution by a worker thread.
|
||||
// If StartCount > 0, Job is deferred until Notify is called StartCount times on the returned IMycSubscriber.
|
||||
// If StartCount <= 0, Job is enqueued immediately.
|
||||
// Returns IMycSubscriber for deferred jobs, or TMycLatch.Null for immediate jobs or if Job is nil.
|
||||
// Exceptions during Job execution are caught; the first one is stored
|
||||
// and can be re-raised in the main thread via WaitFor or Teardown.
|
||||
// Raises ETaskException if the factory is already terminated.
|
||||
function Run(Job: TProc): TSignal.ISubscriber;
|
||||
|
||||
procedure EnqueueJob(const Job: TProc);
|
||||
|
||||
// Shuts down the task factory: terminates worker threads and cleans up resources.
|
||||
// Before shutdown, any first stored exception from a worker thread (from Run or CreateThread tasks managed by this factory)
|
||||
// Before shutdown, any first stored exception from a worker thread (from CreateThread tasks managed by this factory)
|
||||
// will be re-raised in the calling (main) thread.
|
||||
procedure Teardown;
|
||||
|
||||
@@ -49,7 +34,7 @@ type
|
||||
property ThreadCount: Integer read GetThreadCount;
|
||||
end;
|
||||
|
||||
TMycTaskFactory = class(TInterfacedObject, TTaskManager.IMycTaskManager, IMycThreadPool)
|
||||
TMycTaskFactory = class(TInterfacedObject, TTaskManager.ITaskManager, IThreadPool)
|
||||
type
|
||||
ETaskException = class(Exception)
|
||||
end;
|
||||
@@ -75,10 +60,9 @@ type
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
class function CreateAnonymousThread(const DbgName: String; const Proc: TProc): TThread;
|
||||
function CreateThread(const Proc: TProc): TState.IState;
|
||||
procedure CreateThread(const Proc: TProc);
|
||||
procedure HandleException;
|
||||
procedure EnqueueJob(const Job: TProc);
|
||||
function Run(Job: TProc): TSignal.ISubscriber;
|
||||
procedure RunTask(const Gate: TState; const Proc: TProc);
|
||||
procedure WaitFor(const State: TState);
|
||||
procedure Teardown;
|
||||
@@ -188,41 +172,37 @@ end;
|
||||
|
||||
procedure TMycTaskFactory.RunTask(const Gate: TState; const Proc: TProc);
|
||||
begin
|
||||
if not Assigned(Proc) then
|
||||
exit;
|
||||
|
||||
if FTerminated <> 0 then
|
||||
raise ETaskException.Create('Task factory terminated');
|
||||
|
||||
if Gate.IsSet then
|
||||
begin
|
||||
EnqueueJob(Proc);
|
||||
end
|
||||
else
|
||||
begin
|
||||
// The job will run when Gate notifies the subscriber returned by Run.
|
||||
Gate.Signal.Subscribe(Run(Proc));
|
||||
// Create a pending job
|
||||
Gate.Signal.Subscribe(TMycPendingJob.Create(Self, Proc));
|
||||
end;
|
||||
end;
|
||||
|
||||
function TMycTaskFactory.CreateThread(const Proc: TProc): TState.IState;
|
||||
var
|
||||
res: TLatch.ILatch;
|
||||
capturedProc: TProc;
|
||||
procedure TMycTaskFactory.CreateThread(const Proc: TProc);
|
||||
begin
|
||||
// Create a latch that will be signaled when the proc finishes
|
||||
res := TLatch.CreateLatch(1);
|
||||
|
||||
capturedProc := Proc; // Capture Proc for the anonymous method
|
||||
var cProc := Proc; // Capture Proc for the anonymous method
|
||||
CreateAnonymousThread(
|
||||
'Thread',
|
||||
procedure
|
||||
begin
|
||||
try
|
||||
capturedProc(); // Execute the provided procedure
|
||||
cProc(); // Execute the provided procedure
|
||||
finally
|
||||
capturedProc := nil; // Clear the captured proc
|
||||
res.Notify; // Signal completion via the latch's Notify method
|
||||
cProc := nil; // Clear the captured proc
|
||||
end;
|
||||
end)
|
||||
.Start;
|
||||
|
||||
// Return the state interface of the latch
|
||||
exit(res.State);
|
||||
end;
|
||||
|
||||
procedure TMycTaskFactory.EnqueueJob(const Job: TProc);
|
||||
@@ -287,18 +267,6 @@ begin
|
||||
exit(false); // Not found in worker thread list
|
||||
end;
|
||||
|
||||
function TMycTaskFactory.Run(Job: TProc): TSignal.ISubscriber;
|
||||
begin
|
||||
if FTerminated <> 0 then
|
||||
raise ETaskException.Create('Task factory terminated');
|
||||
|
||||
if not Assigned(Job) then
|
||||
exit(TLatch.Null); // Already correct, uses direct static property on TMycLatch
|
||||
|
||||
// Create a pending job
|
||||
Result := TMycPendingJob.Create(Self, Job);
|
||||
end;
|
||||
|
||||
procedure TMycTaskFactory.Teardown;
|
||||
var
|
||||
i: Integer;
|
||||
|
||||
Reference in New Issue
Block a user