
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@6307 8e941d3f-bd1b-0410-a28a-d453659cc2b4
804 lines
18 KiB
ObjectPascal
804 lines
18 KiB
ObjectPascal
{
|
|
Multi thread Queue,witch can be used without multi-thread (c) 2014 ti_dic
|
|
|
|
This library is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU Library General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or (at your
|
|
option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
|
|
for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; if not, write to the Free Software Foundation,
|
|
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
}
|
|
unit mvJobQueue;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils,syncobjs,contnrs,forms;
|
|
|
|
const ALL_TASK_COMPLETED = -1;
|
|
NO_MORE_TASK = 0;
|
|
|
|
type
|
|
TjobQueue = class;
|
|
|
|
{ TJob }
|
|
|
|
TJob = Class
|
|
private
|
|
FLauncher : TObject;
|
|
FCancelled : Boolean;
|
|
FName: String;
|
|
protected
|
|
Queue : TJobQueue;
|
|
|
|
procedure DoCancel;virtual;
|
|
Procedure WaitForResultOf(aJob : TJob);
|
|
Procedure EnterCriticalSection;
|
|
procedure LeaveCriticalSection;
|
|
|
|
//should be called inside critical section
|
|
function pGetTask : integer;virtual;
|
|
procedure pTaskStarted(aTask: integer);virtual;abstract;
|
|
procedure pTaskEnded(aTask : integer;aExcept : Exception);virtual;abstract;
|
|
property Launcher : TObject read FLauncher;
|
|
public
|
|
procedure ExecuteTask(aTask : integer;FromWaiting : boolean);virtual;abstract;
|
|
function Running : boolean;virtual;abstract;
|
|
procedure Cancel;
|
|
property Cancelled : boolean read FCancelled;
|
|
property Name : String read FName write FName;
|
|
end;
|
|
|
|
TJobArray = Array of TJob;
|
|
|
|
{ TjobQueue }
|
|
|
|
TjobQueue = Class
|
|
private
|
|
FMainThreadId : TThreadID;
|
|
FOnIdle: TNotifyEvent;
|
|
waitings : TStringList;
|
|
FNbThread : integer;
|
|
TerminatedThread : integer;
|
|
FSect : TCriticalSection;
|
|
FEvent,TerminateEvent : TEvent;
|
|
FUseThreads: boolean;
|
|
Threads : TList;
|
|
Jobs : TObjectList;
|
|
procedure pJobCompleted(var aJob: TJob);
|
|
procedure SetUseThreads(AValue: boolean);
|
|
procedure ClearWaitings;
|
|
protected
|
|
Procedure InitThreads;
|
|
Procedure FreeThreads;
|
|
Procedure EnterCriticalSection;
|
|
procedure LeaveCriticalSection;
|
|
Procedure DoWaiting(E : Exception;TaskId : integer);
|
|
|
|
//Should be called inside critical section
|
|
procedure pAddWaiting(aJob : TJob;aTask : integer;JobId : String);
|
|
procedure pTaskStarted(aJob : TJob;aTask : integer);
|
|
procedure pTaskEnded(var aJob : TJob;aTask : integer;aExcept : Exception);
|
|
function pGetJob(out TaskId : integer;out Restart : boolean) : TJob;
|
|
function pFindJobByName(const aName : string;ByLauncher: TObject) : TJobArray;
|
|
procedure pNotifyWaitings(aJob : TJob);
|
|
Function IsMainThread : boolean;
|
|
public
|
|
constructor Create(NbThread : integer = 5);
|
|
destructor Destroy;override;
|
|
procedure QueueAsyncCall(const AMethod: TDataEvent; Data: PtrInt);
|
|
procedure QueueSyncCall(const AMethod: TDataEvent; Data: PtrInt);
|
|
property UseThreads : boolean read FUseThreads write SetUseThreads;
|
|
Procedure AddJob(aJob : TJob;Launcher : TObject);
|
|
function AddUniqueJob(aJob : TJob;Launcher : TObject) : boolean;
|
|
function CancelAllJob(ByLauncher: TObject) : TJobArray;
|
|
function CancelJobByName(aJobName : String;ByLauncher: TObject) : boolean;
|
|
Procedure WaitForTerminate(const lstJob : TJobArray);
|
|
Procedure WaitAllJobTerminated(ByLauncher: TObject);
|
|
property OnIdle : TNotifyEvent read FOnIdle write FOnIdle;
|
|
end;
|
|
|
|
|
|
implementation
|
|
const
|
|
WAIT_TIME = 3000;
|
|
TERMINATE_TIMEOUT = 1000;
|
|
|
|
|
|
Type
|
|
|
|
{ EWaiting }
|
|
|
|
EWaiting = Class(Exception)
|
|
private
|
|
FLauncher : TJob;
|
|
FNewJob : TJob;
|
|
public
|
|
constructor Create(launcher : TJob;NewJob : TJob);
|
|
end;
|
|
|
|
{ TRestartTask }
|
|
|
|
TRestartTask = Class(TJob)
|
|
private
|
|
FStarted : Boolean;
|
|
FJob : TJob;
|
|
FTask : integer;
|
|
protected
|
|
procedure DoCancel;override;
|
|
procedure pTaskStarted(aTask: integer);override;
|
|
procedure pTaskEnded(aTask : integer;aExcept : Exception);override;
|
|
function pGetTask : integer;override;
|
|
public
|
|
constructor Create(aJob : TJob;aTask : integer);
|
|
procedure ExecuteTask(aTask : integer;FromWaiting : boolean);override;
|
|
function Running : boolean;override;
|
|
end;
|
|
|
|
{ TQueueThread }
|
|
|
|
TQueueThread = Class(TThread)
|
|
private
|
|
MyQueue : TJobqueue;
|
|
function ProcessJob : boolean;
|
|
public
|
|
constructor Create(aQueue: TJobQueue);
|
|
procedure Execute; override;
|
|
end;
|
|
|
|
{ TRestartTask }
|
|
|
|
procedure TRestartTask.DoCancel;
|
|
begin
|
|
FJob.Cancel;
|
|
end;
|
|
|
|
procedure TRestartTask.pTaskStarted(aTask: integer);
|
|
begin
|
|
FStarted := true;
|
|
end;
|
|
|
|
procedure TRestartTask.pTaskEnded(aTask: integer; aExcept: Exception);
|
|
begin
|
|
Queue.pTaskEnded(FJob,FTask,aExcept);
|
|
end;
|
|
|
|
function TRestartTask.pGetTask: integer;
|
|
begin
|
|
if FStarted then
|
|
Result:=inherited pGetTask
|
|
else
|
|
Result:=1;
|
|
end;
|
|
|
|
constructor TRestartTask.Create(aJob: TJob; aTask: integer);
|
|
begin
|
|
FJob:=aJob;
|
|
FTask:=aTask;
|
|
end;
|
|
|
|
procedure TRestartTask.ExecuteTask(aTask: integer; FromWaiting: boolean);
|
|
begin
|
|
FJob.ExecuteTask(FTask,true);
|
|
end;
|
|
|
|
function TRestartTask.Running: boolean;
|
|
begin
|
|
Result:=Fstarted;
|
|
end;
|
|
|
|
{ EWaiting }
|
|
|
|
constructor EWaiting.Create(launcher: TJob; NewJob: TJob);
|
|
begin
|
|
FLauncher:=launcher;
|
|
FNewJob:=NewJob;
|
|
end;
|
|
|
|
{ TQueueThread }
|
|
|
|
function TQueueThread.ProcessJob : boolean;
|
|
var aJob : TJob;
|
|
TaskId : Integer;
|
|
|
|
Procedure SetRes(e : Exception);
|
|
Begin
|
|
MyQueue.EnterCriticalSection;
|
|
Try
|
|
MyQueue.pTaskEnded(aJob,TaskId,nil);
|
|
finally
|
|
MyQueue.LeaveCriticalSection;
|
|
end;
|
|
end;
|
|
var RestartTask : boolean;
|
|
SomeJob : Boolean;
|
|
begin
|
|
Result:=false;
|
|
Repeat
|
|
SomeJob:=false;
|
|
MyQueue.EnterCriticalSection;
|
|
Try
|
|
result:=result or (MyQueue.Jobs.Count>0);
|
|
aJob:=MyQueue.pGetJob(TaskId,RestartTask);
|
|
if Assigned(aJob) then
|
|
Begin
|
|
if TaskId=ALL_TASK_COMPLETED then
|
|
begin
|
|
MyQueue.pJobCompleted(aJob);
|
|
SomeJob := true;
|
|
end
|
|
else
|
|
Begin
|
|
MyQueue.FEvent.ResetEvent;
|
|
if not(RestartTask) then
|
|
MyQueue.pTaskStarted(aJob,TaskId);
|
|
end;
|
|
end;
|
|
finally
|
|
MyQueue.LeaveCriticalSection;
|
|
end;
|
|
if Assigned(aJob) then
|
|
Begin
|
|
SomeJob:=true;
|
|
Try
|
|
aJob.ExecuteTask(TaskId,RestartTask);
|
|
SetRes(nil);
|
|
Except
|
|
on e : Exception do
|
|
if e.InheritsFrom(EWaiting) then
|
|
MyQueue.DoWaiting(e,TaskId)
|
|
else
|
|
SetRes(e);
|
|
end;
|
|
end;
|
|
until SomeJob=false;
|
|
end;
|
|
|
|
constructor TQueueThread.Create(aQueue: TJobQueue);
|
|
begin
|
|
MyQueue := aQueue;
|
|
inherited Create(False);
|
|
end;
|
|
|
|
procedure TQueueThread.Execute;
|
|
var wRes : TWaitResult;
|
|
begin
|
|
while not Terminated do
|
|
begin
|
|
wRes:=MyQueue.FEvent.WaitFor(WAIT_TIME);
|
|
if not(Terminated) then
|
|
Begin
|
|
if not(ProcessJob) then
|
|
if wRes=wrTimeout then
|
|
if Assigned(MyQueue.OnIdle) then
|
|
MyQueue.OnIdle(self);
|
|
end;
|
|
end;
|
|
MyQueue.EnterCriticalSection;
|
|
Try
|
|
inc(MyQueue.TerminatedThread);
|
|
if Assigned(MyQueue.TerminateEvent) then
|
|
if MyQueue.TerminatedThread=MyQueue.Threads.count then
|
|
MyQueue.TerminateEvent.SetEvent;
|
|
finally
|
|
MyQueue.LeaveCriticalSection;
|
|
end;
|
|
end;
|
|
|
|
{ TjobQueue }
|
|
|
|
procedure TjobQueue.SetUseThreads(AValue: boolean);
|
|
begin
|
|
if FUseThreads=AValue then
|
|
Exit;
|
|
FUseThreads:=AValue;
|
|
if Fusethreads then
|
|
InitThreads
|
|
else
|
|
FreeThreads;
|
|
end;
|
|
|
|
procedure TjobQueue.ClearWaitings;
|
|
var i : integer;
|
|
begin
|
|
For i:=0 to pred(Waitings.count) do
|
|
Waitings.Objects[i].Free;
|
|
Waitings.Clear;
|
|
end;
|
|
|
|
procedure TjobQueue.InitThreads;
|
|
var i : integer;
|
|
begin
|
|
Jobs:=TObjectList.Create(true);
|
|
Threads:=TObjectList.Create(true);
|
|
FEvent:=TEvent.Create(nil,true,false,'');
|
|
FSect:=TCriticalSection.Create;
|
|
TerminatedThread := 0;
|
|
For i:=1 to FNbThread do
|
|
Threads.Add(TQueueThread.Create(self));
|
|
end;
|
|
|
|
procedure TjobQueue.FreeThreads;
|
|
var i : integer;
|
|
begin
|
|
if Assigned(Threads) then
|
|
Begin
|
|
TerminateEvent := TEvent.Create(nil,false,false,'');
|
|
Try
|
|
FEvent.SetEvent;
|
|
TerminatedThread:=0;
|
|
For i:=0 to pred(Threads.Count) do
|
|
TQueueThread(Threads[i]).Terminate;
|
|
TerminateEvent.WaitFor(TERMINATE_TIMEOUT);
|
|
FreeAndNil(FSect);
|
|
FreeAndNil(FEvent);
|
|
FreeAndNil(Threads);
|
|
finally
|
|
FreeAndNil(TerminateEvent);
|
|
end;
|
|
FreeAndNil(Jobs);
|
|
end;
|
|
end;
|
|
|
|
procedure TjobQueue.EnterCriticalSection;
|
|
begin
|
|
if Assigned(FSect) and UseThreads then
|
|
FSect.Enter;
|
|
end;
|
|
|
|
procedure TjobQueue.LeaveCriticalSection;
|
|
begin
|
|
if Assigned(FSect) and UseThreads then
|
|
FSect.Leave;
|
|
end;
|
|
|
|
procedure TjobQueue.DoWaiting(E : Exception;TaskId : integer);
|
|
var we : EWaiting;
|
|
begin
|
|
EnterCriticalSection;
|
|
try
|
|
we:=EWaiting(e);
|
|
pAddWaiting(we.FLauncher,TaskId,we.FNewJob.Name);
|
|
AddUniqueJob(we.FNewJob,we.FLauncher.FLauncher);
|
|
finally
|
|
LeaveCriticalSection;
|
|
end;
|
|
end;
|
|
|
|
procedure TjobQueue.pAddWaiting(aJob: TJob; aTask: integer; JobId: String);
|
|
begin
|
|
Waitings.AddObject(JobId,TRestartTask.Create(aJob,aTask));
|
|
end;
|
|
|
|
procedure TjobQueue.pTaskStarted(aJob: TJob; aTask: integer);
|
|
begin
|
|
aJob.pTaskStarted(aTask);
|
|
end;
|
|
|
|
procedure TjobQueue.pJobCompleted(var aJob: TJob);
|
|
Begin
|
|
pNotifyWaitings(aJob);
|
|
if FuseThreads then
|
|
Begin
|
|
Jobs.Remove(aJob);
|
|
aJob:=nil;
|
|
end
|
|
else
|
|
FreeAndNil(aJob);
|
|
end;
|
|
|
|
procedure TjobQueue.pTaskEnded(var aJob: TJob; aTask: integer; aExcept: Exception);
|
|
begin
|
|
aJob.pTaskEnded(aTask,aExcept);
|
|
if (aJob.pGetTask=ALL_TASK_COMPLETED) then
|
|
Begin
|
|
pJobcompleted(aJob);
|
|
end;
|
|
end;
|
|
|
|
function TjobQueue.pGetJob(out TaskId : integer;out Restart : boolean): TJob;
|
|
var iJob : integer;
|
|
aJob : TJob;
|
|
begin
|
|
Restart:=false;
|
|
Result:=nil;
|
|
For iJob:=0 to pred(Jobs.Count) do
|
|
Begin
|
|
aJob:=TJob(Jobs[iJob]);
|
|
if aJob.InheritsFrom(TRestartTask) then
|
|
Begin
|
|
result:=TRestartTask(aJob).FJob;
|
|
TaskId:=TRestartTask(aJob).FTask;
|
|
Restart:=true;
|
|
Jobs.Delete(iJob);
|
|
Exit;
|
|
end;
|
|
TaskId:=aJob.pGetTask;
|
|
if (TaskId>NO_MORE_TASK) or (TaskId=ALL_TASK_COMPLETED) then
|
|
Begin
|
|
Result:=aJob;
|
|
Exit;
|
|
end;
|
|
end;
|
|
if not(assigned(result)) then
|
|
TaskId:=NO_MORE_TASK;
|
|
end;
|
|
|
|
function TjobQueue.pFindJobByName(const aName: string;ByLauncher: TObject): TJobArray;
|
|
var iRes,i : integer;
|
|
begin
|
|
SetLength(result,Jobs.count);
|
|
iRes:=0;
|
|
For i:=0 to pred(Jobs.Count) do
|
|
Begin
|
|
if TJob(Jobs[i]).Name=aName then
|
|
begin
|
|
if (ByLauncher=nil) or (TJob(Jobs[i]).FLauncher=ByLauncher) then
|
|
Begin
|
|
Result[iRes]:=TJob(Jobs[i]);
|
|
inc(iRes);
|
|
end;
|
|
end;
|
|
end;
|
|
SetLength(result,iRes);
|
|
end;
|
|
|
|
procedure TjobQueue.pNotifyWaitings(aJob: TJob);
|
|
var JobId : String;
|
|
ObjRestart : TRestartTask;
|
|
idx : integer;
|
|
begin
|
|
JobId:=aJob.Name;
|
|
Repeat
|
|
idx:=waitings.IndexOf(JobId);
|
|
if idx<>-1 then
|
|
Begin
|
|
ObjRestart:=TRestartTask(waitings.Objects[idx]);
|
|
waitings.Delete(idx);
|
|
Jobs.Add(ObjRestart);
|
|
end;
|
|
until idx=-1;
|
|
end;
|
|
|
|
function TjobQueue.IsMainThread: boolean;
|
|
begin
|
|
Result:=GetCurrentThreadId=FMainThreadID;
|
|
end;
|
|
|
|
constructor TjobQueue.Create(NbThread: integer);
|
|
begin
|
|
waitings:=TStringList.create;
|
|
FNbThread:=NbThread;
|
|
FMainThreadId:=GetCurrentThreadId;
|
|
end;
|
|
|
|
destructor TjobQueue.Destroy;
|
|
begin
|
|
FreeThreads;
|
|
ClearWaitings;
|
|
FreeAndNil(Waitings);
|
|
inherited;
|
|
end;
|
|
|
|
procedure TjobQueue.QueueAsyncCall(const AMethod: TDataEvent; Data: PtrInt);
|
|
begin
|
|
if UseThreads then
|
|
Application.QueueAsyncCall(aMethod,Data)
|
|
else
|
|
AMethod(Data);
|
|
end;
|
|
|
|
|
|
Type
|
|
|
|
{ TSyncCallData }
|
|
|
|
TSyncCallData = Class
|
|
private
|
|
FMethod : TDataEvent;
|
|
FData : PtrInt;
|
|
public
|
|
Constructor Create(AMethod : TDataEvent;AData : PtrInt);
|
|
Procedure SyncCall;
|
|
End;
|
|
|
|
{ TSyncCallData }
|
|
|
|
constructor TSyncCallData.Create(AMethod: TDataEvent; AData: PtrInt);
|
|
begin
|
|
FMethod:=AMethod;
|
|
FData:=AData;
|
|
|
|
end;
|
|
|
|
procedure TSyncCallData.SyncCall;
|
|
begin
|
|
FMethod(FData);
|
|
end;
|
|
|
|
procedure TjobQueue.QueueSyncCall(const AMethod: TDataEvent; Data: PtrInt);
|
|
var tmp : TSyncCallData;
|
|
begin
|
|
tmp := TSyncCallData.Create(AMethod,Data);
|
|
Try
|
|
TThread.Synchronize(nil,@tmp.SyncCall);
|
|
finally
|
|
tmp.free;
|
|
end;
|
|
end;
|
|
|
|
procedure TjobQueue.AddJob(aJob: TJob;Launcher : TObject);
|
|
var TaskId : Integer;
|
|
restart : boolean;
|
|
begin
|
|
aJob.FLauncher:=Launcher;
|
|
aJob.Queue:=self;
|
|
if Usethreads then
|
|
Begin
|
|
EnterCriticalSection;
|
|
Try
|
|
Jobs.add(aJob);
|
|
finally
|
|
LeaveCriticalSection;
|
|
end;
|
|
FEvent.SetEvent;
|
|
end
|
|
Else
|
|
Begin
|
|
Try
|
|
Repeat
|
|
TaskId:=aJob.pGetTask;
|
|
restart:=false;
|
|
if TaskId>NO_MORE_TASK then
|
|
Begin
|
|
pTaskStarted(aJob,TaskId);
|
|
Try
|
|
aJob.ExecuteTask(TaskId,restart);
|
|
pTaskEnded(aJob,TaskId,nil);
|
|
except
|
|
on e : Exception do
|
|
Begin
|
|
if not(e.InheritsFrom(EWaiting)) then
|
|
pTaskEnded(aJob,TaskId,e)
|
|
else
|
|
DoWaiting(e,TaskId);
|
|
end;
|
|
end;
|
|
end;
|
|
if not(Assigned(aJob)) then
|
|
TaskId:=ALL_TASK_COMPLETED;
|
|
until TaskId=ALL_TASK_COMPLETED;
|
|
finally
|
|
aJob.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TjobQueue.AddUniqueJob(aJob: TJob; Launcher: TObject): boolean;
|
|
var lst : TJobArray;
|
|
begin
|
|
Result:=true;
|
|
if FUseThreads then
|
|
Begin
|
|
aJob.Queue:=self;
|
|
aJob.FLauncher:=Launcher;
|
|
EnterCriticalSection;
|
|
Try
|
|
lst:=pFindJobByName(aJob.Name,Launcher);
|
|
if length(lst)=0 then
|
|
Jobs.add(aJob)
|
|
else
|
|
Result:=false;
|
|
finally
|
|
LeaveCriticalSection;
|
|
end;
|
|
FEvent.SetEvent;;
|
|
end
|
|
Else
|
|
AddJob(aJob,Launcher);
|
|
end;
|
|
|
|
function TjobQueue.CancelAllJob(ByLauncher: TObject) : TJobArray;
|
|
var i,iJob : integer;
|
|
begin
|
|
SetLength(Result,0);
|
|
if FUseThreads then
|
|
Begin
|
|
EnterCriticalSection;
|
|
Try
|
|
SetLEngth(Result,Jobs.Count);
|
|
iJob:=0;
|
|
For i:=pred(Jobs.Count) downto 0 do
|
|
Begin
|
|
if (ByLauncher=nil) or (TJob(Jobs[i]).FLauncher=ByLauncher) then
|
|
Begin
|
|
TJob(Jobs[i]).Cancel;
|
|
Result[iJob]:=TJob(Jobs[i]);
|
|
iJob+=1;
|
|
End;
|
|
End;
|
|
SetLength(Result,iJob);
|
|
finally
|
|
LeaveCriticalSection;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TjobQueue.CancelJobByName(aJobName: String;ByLauncher: TObject) : boolean;
|
|
var lst : TJobArray;
|
|
i : integer;
|
|
begin
|
|
Result:=false;
|
|
if FUseThreads then
|
|
Begin
|
|
EnterCriticalSection;
|
|
Try
|
|
lst:=pFindJobByName(aJobName,ByLauncher);
|
|
For i:=low(lst) to high(lst) do
|
|
Begin
|
|
result:=true;
|
|
lst[i].Cancel;
|
|
End;
|
|
finally
|
|
LeaveCriticalSection;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TjobQueue.WaitForTerminate(const lstJob: TJobArray);
|
|
var OneFound : Boolean;
|
|
i : integer;
|
|
mThread : Boolean;
|
|
TimeOut : integer;
|
|
begin
|
|
TimeOut:=0;
|
|
mThread:=IsMainThread;
|
|
if FUseThreads then
|
|
Begin
|
|
repeat
|
|
OneFound:=False;
|
|
EnterCriticalSection;
|
|
Try
|
|
For i:=low(lstJob) to high(lstJob) do
|
|
Begin
|
|
if Jobs.IndexOf(lstJob[i])<>-1 then
|
|
Begin
|
|
OneFound:=True;
|
|
break;
|
|
end;
|
|
end;
|
|
finally
|
|
LeaveCriticalSection;
|
|
end;
|
|
if OneFound and (TimeOut>200) then
|
|
Raise Exception.Create('TimeOut');
|
|
if mThread then
|
|
Application.ProcessMessages;
|
|
if OneFound then
|
|
Sleep(100);
|
|
Inc(TimeOut);
|
|
until not(OneFound);
|
|
end;
|
|
end;
|
|
|
|
procedure TjobQueue.WaitAllJobTerminated(ByLauncher: TObject);
|
|
var OneFound : boolean;
|
|
i : integer;
|
|
TimeOut : integer;
|
|
mThread : Boolean;
|
|
|
|
Procedure CheckTimeOut;
|
|
Begin
|
|
if TimeOut>200 then
|
|
Raise Exception.Create('TimeOut');
|
|
if mThread then
|
|
Application.ProcessMessages;
|
|
sleep(100);
|
|
inc(TimeOut);
|
|
end;
|
|
|
|
begin
|
|
TimeOut:=0;
|
|
if FUseThreads then
|
|
Begin
|
|
mThread:=IsMainThread;
|
|
if ByLauncher=nil then
|
|
Begin
|
|
While Jobs.Count>0 do
|
|
CheckTimeOut;
|
|
end
|
|
else
|
|
Begin
|
|
repeat
|
|
OneFound:=False;
|
|
EnterCriticalSection;
|
|
Try
|
|
For i:=0 to pred(Jobs.Count) do
|
|
Begin
|
|
if TJob(Jobs[i]).FLauncher=ByLauncher then
|
|
Begin
|
|
OneFound:=True;
|
|
break;
|
|
end;
|
|
end;
|
|
finally
|
|
LeaveCriticalSection;
|
|
end;
|
|
if OneFound then
|
|
CheckTimeOut;
|
|
until not(OneFound);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{ TjobQueue }
|
|
|
|
procedure TJob.Cancel;
|
|
var lst : Array of TRestartTask;
|
|
i,idx : integer;
|
|
begin
|
|
Queue.EnterCriticalSection;
|
|
Try
|
|
FCancelled := true;
|
|
if (Name<>'') and (Queue.waitings.count>0) then
|
|
Begin
|
|
SetLength(lst,0);
|
|
Repeat
|
|
idx:=Queue.waitings.IndexOf(Name);
|
|
if idx<>-1 then
|
|
Begin
|
|
SetLength(lst,length(lst)+1);
|
|
lst[high(lst)]:=TRestartTask(Queue.waitings.Objects[idx]);
|
|
Queue.waitings.Delete(idx);
|
|
end;
|
|
until idx=-1;
|
|
For i:=low(lst) to high(lst) do
|
|
Begin
|
|
lst[i].Cancel;
|
|
lst[i].pTaskEnded(1,nil);
|
|
lst[i].Free;
|
|
end;
|
|
end;
|
|
DoCancel;
|
|
finally
|
|
Queue.LeaveCriticalSection;
|
|
end;
|
|
end;
|
|
|
|
procedure TJob.DoCancel;
|
|
begin
|
|
|
|
end;
|
|
|
|
function TJob.pGetTask: integer;
|
|
begin
|
|
result:=ALL_TASK_COMPLETED;
|
|
end;
|
|
|
|
procedure TJob.WaitForResultOf(aJob: TJob);
|
|
begin
|
|
Raise EWaiting.Create(self,aJob);
|
|
end;
|
|
|
|
procedure TJob.EnterCriticalSection;
|
|
begin
|
|
Queue.EnterCriticalSection;
|
|
end;
|
|
|
|
procedure TJob.LeaveCriticalSection;
|
|
begin
|
|
Queue.LeaveCriticalSection;
|
|
end;
|
|
|
|
end.
|
|
|