refactoring tasks
This commit is contained in:
+21
-28
@@ -32,7 +32,9 @@ type
|
||||
// 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(StartCount: Integer; Job: TProc): IMycSubscriber;
|
||||
function Run(Job: TProc): IMycSubscriber;
|
||||
|
||||
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)
|
||||
@@ -67,7 +69,6 @@ type
|
||||
procedure WorkerThread;
|
||||
|
||||
protected
|
||||
procedure EnqueueJob(const Job: TProc);
|
||||
procedure ExecuteJob;
|
||||
function GetThreadCount: Integer;
|
||||
property WaitSemaphores: TMycAtomicStack<TSemaphore> read FWaitSemaphores;
|
||||
@@ -78,7 +79,8 @@ type
|
||||
class function CreateAnonymousThread(const DbgName: String; const Proc: TProc): TThread;
|
||||
function CreateThread(const Proc: TProc): IMycState;
|
||||
procedure HandleException;
|
||||
function Run(StartCount: Integer; Job: TProc): IMycSubscriber;
|
||||
procedure EnqueueJob(const Job: TProc);
|
||||
function Run(Job: TProc): IMycSubscriber;
|
||||
procedure WaitFor(State: IMycState);
|
||||
procedure Teardown;
|
||||
function InMainThread: Boolean;
|
||||
@@ -91,7 +93,6 @@ type
|
||||
TMycPendingJob = class(TInterfacedObject, IMycSubscriber)
|
||||
private
|
||||
[volatile]
|
||||
FCount: Integer; // Countdown counter
|
||||
FJob: TProc; // The job to execute when count reaches zero
|
||||
FOwner: TMycTaskFactory; // The task factory to enqueue the job on
|
||||
|
||||
@@ -99,7 +100,7 @@ type
|
||||
function Notify: Boolean;
|
||||
|
||||
public
|
||||
constructor Create(StartCountValue: Integer; OwnerTaskFactory: TMycTaskFactory; const JobProc: TProc);
|
||||
constructor Create(OwnerTaskFactory: TMycTaskFactory; const JobProc: TProc);
|
||||
property Owner: TMycTaskFactory read FOwner;
|
||||
end;
|
||||
|
||||
@@ -200,6 +201,9 @@ end;
|
||||
|
||||
procedure TMycTaskFactory.EnqueueJob(const Job: TProc);
|
||||
begin
|
||||
if FTerminated <> 0 then
|
||||
raise ETaskException.Create('Task factory terminated');
|
||||
|
||||
if Assigned(Job) then
|
||||
begin
|
||||
FWorkStack.Push(Job); // Push job onto the lock-free stack
|
||||
@@ -257,7 +261,7 @@ begin
|
||||
exit(false); // Not found in worker thread list
|
||||
end;
|
||||
|
||||
function TMycTaskFactory.Run(StartCount: Integer; Job: TProc): IMycSubscriber;
|
||||
function TMycTaskFactory.Run(Job: TProc): IMycSubscriber;
|
||||
begin
|
||||
if FTerminated <> 0 then
|
||||
raise ETaskException.Create('Task factory terminated');
|
||||
@@ -265,14 +269,8 @@ begin
|
||||
if not Assigned(Job) then
|
||||
exit(TMycLatch.Null); // Already correct, uses direct static property on TMycLatch
|
||||
|
||||
if StartCount <= 0 then
|
||||
begin
|
||||
EnqueueJob(Job); // Enqueue immediately if no countdown needed
|
||||
Result := TMycLatch.Null; // Already correct
|
||||
end
|
||||
else
|
||||
// Create a pending job that waits for StartCount notifications
|
||||
Result := TMycPendingJob.Create(StartCount, Self, Job);
|
||||
// Create a pending job
|
||||
Result := TMycPendingJob.Create(Self, Job);
|
||||
end;
|
||||
|
||||
procedure TMycTaskFactory.Teardown;
|
||||
@@ -353,11 +351,10 @@ end;
|
||||
|
||||
{ TMycPendingJob }
|
||||
|
||||
constructor TMycPendingJob.Create(StartCountValue: Integer; OwnerTaskFactory: TMycTaskFactory; const JobProc: TProc);
|
||||
constructor TMycPendingJob.Create(OwnerTaskFactory: TMycTaskFactory; const
|
||||
JobProc: TProc);
|
||||
begin
|
||||
inherited Create;
|
||||
Assert(StartCountValue > 0);
|
||||
FCount := StartCountValue;
|
||||
FOwner := OwnerTaskFactory;
|
||||
FJob := JobProc;
|
||||
end;
|
||||
@@ -365,20 +362,16 @@ end;
|
||||
function TMycPendingJob.Notify: Boolean;
|
||||
var
|
||||
newCount: Integer;
|
||||
P: TProc;
|
||||
begin
|
||||
newCount := TInterlocked.Decrement(FCount);
|
||||
if newCount < -MaxInt div 2 then
|
||||
TInterlocked.Increment(FCount);
|
||||
|
||||
if newCount = 0 then
|
||||
PPointer(@P)^ := TInterlocked.Exchange( PPointer(@FJob)^, nil );
|
||||
Result := Assigned(P);
|
||||
if Result then
|
||||
begin
|
||||
if Assigned(FOwner) and Assigned(FJob) then
|
||||
begin
|
||||
FOwner.EnqueueJob(FJob);
|
||||
FJob := nil;
|
||||
end;
|
||||
if Assigned(FOwner) then
|
||||
FOwner.EnqueueJob(P);
|
||||
P := nil;
|
||||
end;
|
||||
Result := newCount > 0;
|
||||
end;
|
||||
|
||||
{ TMycTaskWait }
|
||||
|
||||
Reference in New Issue
Block a user