Browse Source

Merge branch 'develop'

Unknown 6 years ago
parent
commit
c4e505b218

+ 184 - 28
Quick.Threads.pas

@@ -142,21 +142,38 @@ type
   TProc = procedure of object;
   TProc = procedure of object;
   {$ENDIF}
   {$ENDIF}
 
 
+  TAdvThread = class(TThread)
+  private
+    fExecuteProc : TProc;
+    fTerminateProc : TProc;
+    fExecuteWithSync : Boolean;
+    fTerminateWithSync : Boolean;
+    procedure DoExecute;
+    procedure CallToTerminate;
+  protected
+    procedure DoTerminate; override;
+  public
+    constructor Create(aProc : TProc; aSynchronize : Boolean);
+    procedure OnTerminate(aProc : TProc; aSynchronize : Boolean);
+    procedure Execute; override;
+  end;
+
   IAnonymousThread = interface
   IAnonymousThread = interface
     procedure Start;
     procedure Start;
     function OnTerminate(aProc : TProc) : IAnonymousThread;
     function OnTerminate(aProc : TProc) : IAnonymousThread;
+    function OnTerminate_Sync(aProc : TProc) : IAnonymousThread;
   end;
   end;
 
 
   TAnonymousThread = class(TInterfacedObject,IAnonymousThread)
   TAnonymousThread = class(TInterfacedObject,IAnonymousThread)
   private
   private
-    fThread : TThread;
-    fTerminateProc : TProc;
-    constructor Create(aProc : TProc);
-    procedure NotifyTerminate(Sender : TObject);
+    fThread : TAdvThread;
+    constructor Create(aProc : TProc; aSynchronize : Boolean);
   public
   public
-    class function Execute(aProc : TProc) : IAnonymousThread;
+    class function Execute(aProc : TProc) : IAnonymousThread; overload;
+    class function Execute_Sync(aProc : TProc) : IAnonymousThread; overload;
     procedure Start;
     procedure Start;
-    function OnTerminate(aProc : TProc) : IAnonymousThread;
+    function OnTerminate(aProc : TProc) : IAnonymousThread; overload;
+    function OnTerminate_Sync(aProc : TProc) : IAnonymousThread; overload;
   end;
   end;
 
 
   TParamArray = array of TFlexValue;
   TParamArray = array of TFlexValue;
@@ -201,8 +218,11 @@ type
   IScheduledTask = interface(ITask)
   IScheduledTask = interface(ITask)
   ['{AE551638-ECDE-4F64-89BF-F07BFCB9C9F7}']
   ['{AE551638-ECDE-4F64-89BF-F07BFCB9C9F7}']
     function OnException(aTaskProc : TTaskExceptionProc) : IScheduledTask;
     function OnException(aTaskProc : TTaskExceptionProc) : IScheduledTask;
+    function OnException_Sync(aTaskProc : TTaskExceptionProc) : IScheduledTask;
     function OnTerminated(aTaskProc : TTaskProc) : IScheduledTask;
     function OnTerminated(aTaskProc : TTaskProc) : IScheduledTask;
+    function OnTerminated_Sync(aTaskProc : TTaskProc) : IScheduledTask;
     function OnExpired(aTaskProc : TTaskProc) : IScheduledTask;
     function OnExpired(aTaskProc : TTaskProc) : IScheduledTask;
+    function OnExpired_Sync(aTaskProc : TTaskProc) : IScheduledTask;
     function CheckSchedule : Boolean;
     function CheckSchedule : Boolean;
     procedure DoExpire;
     procedure DoExpire;
     function GetTaskName : string;
     function GetTaskName : string;
@@ -228,6 +248,9 @@ type
     fTaskStatus : TWorkTaskStatus;
     fTaskStatus : TWorkTaskStatus;
     fOwnedParams : Boolean;
     fOwnedParams : Boolean;
     fEnabled : Boolean;
     fEnabled : Boolean;
+    fExecuteWithSync : Boolean;
+    fExceptionWithSync : Boolean;
+    fTerminateWithSync : Boolean;
     function GetParam(aIndex : Integer) : TFlexValue;
     function GetParam(aIndex : Integer) : TFlexValue;
     procedure DoExecute;
     procedure DoExecute;
     procedure DoException(aException : Exception);
     procedure DoException(aException : Exception);
@@ -236,6 +259,10 @@ type
     procedure SetNumWorker(Value : Integer);
     procedure SetNumWorker(Value : Integer);
     function GetIdTask : Int64;
     function GetIdTask : Int64;
     procedure SetIdTask(Value : Int64);
     procedure SetIdTask(Value : Int64);
+  protected
+    property ExecuteWithSync : Boolean read fExecuteWithSync write fExecuteWithSync;
+    property TerminateWithSync : Boolean read fTerminateWithSync write fTerminateWithSync;
+    property ExceptionWithSync : Boolean read fExceptionWithSync write fExceptionWithSync;
   public
   public
     constructor Create(aParamArray : array of const; aOwnedParams : Boolean; aTaskProc : TTaskProc); virtual;
     constructor Create(aParamArray : array of const; aOwnedParams : Boolean; aTaskProc : TTaskProc); virtual;
     destructor Destroy; override;
     destructor Destroy; override;
@@ -267,15 +294,21 @@ type
     fExpirationDate : TDateTime;
     fExpirationDate : TDateTime;
     fExpirationTimes : Integer;
     fExpirationTimes : Integer;
     fFinished : Boolean;
     fFinished : Boolean;
+    fExpireWithSync: Boolean;
     procedure ClearSchedule;
     procedure ClearSchedule;
     function CheckSchedule : Boolean;
     function CheckSchedule : Boolean;
     procedure DoExpire;
     procedure DoExpire;
     function GetTaskName : string;
     function GetTaskName : string;
+  protected
+    property ExpireWithSync : Boolean read fExpireWithSync write fExpireWithSync;
   public
   public
     property Name : string read fName write fName;
     property Name : string read fName write fName;
     function OnException(aTaskProc : TTaskExceptionProc) : IScheduledTask; virtual;
     function OnException(aTaskProc : TTaskExceptionProc) : IScheduledTask; virtual;
+    function OnException_Sync(aTaskProc : TTaskExceptionProc) : IScheduledTask; virtual;
     function OnTerminated(aTaskProc : TTaskProc) : IScheduledTask; virtual;
     function OnTerminated(aTaskProc : TTaskProc) : IScheduledTask; virtual;
+    function OnTerminated_Sync(aTaskProc : TTaskProc) : IScheduledTask; virtual;
     function OnExpired(aTaskProc : TTaskProc) : IScheduledTask; virtual;
     function OnExpired(aTaskProc : TTaskProc) : IScheduledTask; virtual;
+    function OnExpired_Sync(aTaskProc : TTaskProc) : IScheduledTask; virtual;
     function StartAt(aStartDate : TDateTime) : IScheduledTask;
     function StartAt(aStartDate : TDateTime) : IScheduledTask;
     procedure RunOnce;
     procedure RunOnce;
     procedure RepeatEvery(aInterval : Integer; aTimeMeasure : TTimeMeasure); overload;
     procedure RepeatEvery(aInterval : Integer; aTimeMeasure : TTimeMeasure); overload;
@@ -291,9 +324,12 @@ type
   private
   private
     fNumWorker : Integer;
     fNumWorker : Integer;
     fCurrentIdTask : Integer;
     fCurrentIdTask : Integer;
-    fCurrentTask : IWorkTask;
     fStatus : TWorkerStatus;
     fStatus : TWorkerStatus;
     fTaskQueue : TTaskQueue;
     fTaskQueue : TTaskQueue;
+    procedure ExecuteTask;
+    procedure TerminateTask;
+  protected
+    fCurrentTask : ITask;
   public
   public
     constructor Create(aNumWorker : Integer; aTaskQueue : TTaskQueue);
     constructor Create(aNumWorker : Integer; aTaskQueue : TTaskQueue);
     property NumWorker : Integer read fNumWorker;
     property NumWorker : Integer read fNumWorker;
@@ -303,7 +339,7 @@ type
 
 
   TScheduledWorker = class(TWorker)
   TScheduledWorker = class(TWorker)
   private
   private
-    fTask : IScheduledTask;
+    procedure ExpireTask;
   public
   public
     constructor Create(aNumWorker : Integer; aScheduledTask: IScheduledTask);
     constructor Create(aNumWorker : Integer; aScheduledTask: IScheduledTask);
     procedure Execute; override;
     procedure Execute; override;
@@ -331,7 +367,9 @@ type
     property NumPushedTasks : Int64 read fNumPushedTasks;
     property NumPushedTasks : Int64 read fNumPushedTasks;
     property ConcurrentWorkers : Integer read fConcurrentWorkers write fConcurrentWorkers;
     property ConcurrentWorkers : Integer read fConcurrentWorkers write fConcurrentWorkers;
     function AddTask(aTaskProc : TTaskProc) : IWorkTask; overload;
     function AddTask(aTaskProc : TTaskProc) : IWorkTask; overload;
+    function AddTask_Sync(aTaskProc : TTaskProc) : IWorkTask; overload;
     function AddTask(aParamArray : array of const; aOwnedParams : Boolean; aTaskProc : TTaskProc) : IWorkTask; overload;
     function AddTask(aParamArray : array of const; aOwnedParams : Boolean; aTaskProc : TTaskProc) : IWorkTask; overload;
+    function AddTask_Sync(aParamArray : array of const; aOwnedParams : Boolean; aTaskProc : TTaskProc) : IWorkTask; overload;
     procedure Start;
     procedure Start;
     procedure CancelAll;
     procedure CancelAll;
   end;
   end;
@@ -344,6 +382,7 @@ type
     fCondVar : TSimpleEvent;
     fCondVar : TSimpleEvent;
     fTaskList : TScheduledTaskList;
     fTaskList : TScheduledTaskList;
     fRemoveTaskAfterExpiration : Boolean;
     fRemoveTaskAfterExpiration : Boolean;
+    procedure ExpireTask;
   public
   public
     constructor Create(aTaskList : TScheduledTaskList);
     constructor Create(aTaskList : TScheduledTaskList);
     destructor Destroy; override;
     destructor Destroy; override;
@@ -368,7 +407,9 @@ type
     property RemoveTaskAfterExpiration : Boolean read fRemoveTaskAfterExpiration write fRemoveTaskAfterExpiration;
     property RemoveTaskAfterExpiration : Boolean read fRemoveTaskAfterExpiration write fRemoveTaskAfterExpiration;
     property IsStarted : Boolean read fIsStarted;
     property IsStarted : Boolean read fIsStarted;
     function AddTask(const aTaskName : string; aTaskProc : TTaskProc) : IScheduledTask; overload;
     function AddTask(const aTaskName : string; aTaskProc : TTaskProc) : IScheduledTask; overload;
+    function AddTask_Sync(const aTaskName : string; aTaskProc : TTaskProc) : IScheduledTask; overload;
     function AddTask(const aTaskName : string; aParamArray : array of const; aOwnedParams : Boolean; aTaskProc : TTaskProc) : IScheduledTask; overload;
     function AddTask(const aTaskName : string; aParamArray : array of const; aOwnedParams : Boolean; aTaskProc : TTaskProc) : IScheduledTask; overload;
+    function AddTask_Sync(const aTaskName : string; aParamArray : array of const; aOwnedParams : Boolean; aTaskProc : TTaskProc) : IScheduledTask; overload;
     function GetTask(aIdTask : Int64) : IScheduledTask; overload;
     function GetTask(aIdTask : Int64) : IScheduledTask; overload;
     function GetTask(const aTaskName : string) : IScheduledTask; overload;
     function GetTask(const aTaskName : string) : IScheduledTask; overload;
     procedure Start;
     procedure Start;
@@ -837,30 +878,31 @@ end;
 
 
 { TAnonymousThread }
 { TAnonymousThread }
 
 
-constructor TAnonymousThread.Create(aProc : TProc);
+constructor TAnonymousThread.Create(aProc : TProc; aSynchronize : Boolean);
 begin
 begin
-  {$IFNDEF FPC}
-  fThread := TThread.CreateAnonymousThread(aProc);
-  {$ELSE}
-  fThread := TThread.CreateAnonymousThread(@aProc);
-  {$ENDIF}
+  fThread := TAdvThread.Create(aProc,aSynchronize);
 end;
 end;
 
 
 class function TAnonymousThread.Execute(aProc: TProc): IAnonymousThread;
 class function TAnonymousThread.Execute(aProc: TProc): IAnonymousThread;
 begin
 begin
-  Result := TAnonymousThread.Create(aProc);
+  Result := TAnonymousThread.Create(aProc,False);
 end;
 end;
 
 
-procedure TAnonymousThread.NotifyTerminate(Sender: TObject);
+class function TAnonymousThread.Execute_Sync(aProc: TProc): IAnonymousThread;
 begin
 begin
-  fTerminateProc;
+  Result := TAnonymousThread.Create(aProc,True);
 end;
 end;
 
 
 function TAnonymousThread.OnTerminate(aProc: TProc): IAnonymousThread;
 function TAnonymousThread.OnTerminate(aProc: TProc): IAnonymousThread;
 begin
 begin
   Result := Self;
   Result := Self;
-  fTerminateProc := aProc;
-  fThread.OnTerminate := Self.NotifyTerminate;
+  fThread.OnTerminate(aProc,False);
+end;
+
+function TAnonymousThread.OnTerminate_Sync(aProc: TProc): IAnonymousThread;
+begin
+  Result := Self;
+  fThread.OnTerminate(aProc,True);
 end;
 end;
 
 
 procedure TAnonymousThread.Start;
 procedure TAnonymousThread.Start;
@@ -875,6 +917,9 @@ var
   i : Integer;
   i : Integer;
 begin
 begin
   fTaskStatus := TWorkTaskStatus.wtsPending;
   fTaskStatus := TWorkTaskStatus.wtsPending;
+  fExecuteWithSync := False;
+  fTerminateWithSync := False;
+  fExceptionWithSync := False;
   fOwnedParams := aOwnedParams;
   fOwnedParams := aOwnedParams;
   SetLength(fParamArray,High(aParamArray)+1);
   SetLength(fParamArray,High(aParamArray)+1);
   for i := Low(aParamArray) to High(aParamArray) do
   for i := Low(aParamArray) to High(aParamArray) do
@@ -1028,6 +1073,17 @@ begin
   end;
   end;
 end;
 end;
 
 
+function TBackgroundTasks.AddTask_Sync(aParamArray: array of const; aOwnedParams: Boolean; aTaskProc: TTaskProc): IWorkTask;
+begin
+  Result := AddTask(aParamArray,aOwnedParams,aTaskProc);
+  TTask(Result).ExecuteWithSync := True;
+end;
+
+function TBackgroundTasks.AddTask_Sync(aTaskProc: TTaskProc): IWorkTask;
+begin
+  Result := AddTask_Sync([],False,aTaskProc);
+end;
+
 procedure TBackgroundTasks.Start;
 procedure TBackgroundTasks.Start;
 var
 var
   i : Integer;
   i : Integer;
@@ -1055,6 +1111,16 @@ begin
   FreeOnTerminate := False;
   FreeOnTerminate := False;
 end;
 end;
 
 
+procedure TWorker.ExecuteTask;
+begin
+  fCurrentTask.DoExecute;
+end;
+
+procedure TWorker.TerminateTask;
+begin
+  fCurrentTask.DoTerminate;
+end;
+
 procedure TWorker.Execute;
 procedure TWorker.Execute;
 begin
 begin
   fStatus := TWorkerStatus.wsIdle;
   fStatus := TWorkerStatus.wsIdle;
@@ -1066,7 +1132,8 @@ begin
       fStatus := TWorkerStatus.wsWorking;
       fStatus := TWorkerStatus.wsWorking;
       try
       try
         fCurrentIdTask := fCurrentTask.GetIdTask;
         fCurrentIdTask := fCurrentTask.GetIdTask;
-        fCurrentTask.DoExecute;
+        if TTask(fCurrentTask).ExecuteWithSync then Synchronize(ExecuteTask)
+          else fCurrentTask.DoExecute;
       except
       except
         on E : Exception do
         on E : Exception do
         begin
         begin
@@ -1075,7 +1142,8 @@ begin
         end;
         end;
       end;
       end;
     finally
     finally
-      fCurrentTask.DoTerminate;
+      if TTask(fCurrentTask).TerminateWithSync then Synchronize(TerminateTask)
+        else fCurrentTask.DoTerminate;
       fStatus := TWorkerStatus.wsIdle;
       fStatus := TWorkerStatus.wsIdle;
     end;
     end;
   end;
   end;
@@ -1101,6 +1169,17 @@ begin
   Result := scheduletask;
   Result := scheduletask;
 end;
 end;
 
 
+function TScheduledTasks.AddTask_Sync(const aTaskName: string; aParamArray: array of const; aOwnedParams: Boolean; aTaskProc: TTaskProc): IScheduledTask;
+begin
+  Result := AddTask(aTaskName,aParamArray,aOwnedParams,aTaskProc);
+  TTask(Result).ExecuteWithSync := True;
+end;
+
+function TScheduledTasks.AddTask_Sync(const aTaskName: string; aTaskProc: TTaskProc): IScheduledTask;
+begin
+  Result := AddTask_Sync(aTaskName,aTaskProc);
+end;
+
 constructor TScheduledTasks.Create;
 constructor TScheduledTasks.Create;
 begin
 begin
   fNumPushedTasks := 0;
   fNumPushedTasks := 0;
@@ -1284,52 +1363,84 @@ begin
   Result := Self;
   Result := Self;
 end;
 end;
 
 
+function TScheduledTask.OnException_Sync(aTaskProc: TTaskExceptionProc): IScheduledTask;
+begin
+  Result := OnException(aTaskProc);
+  TTask(Result).ExceptionWithSync := True;
+end;
+
 function TScheduledTask.OnExpired(aTaskProc: TTaskProc): IScheduledTask;
 function TScheduledTask.OnExpired(aTaskProc: TTaskProc): IScheduledTask;
 begin
 begin
   fExpiredProc := aTaskProc;
   fExpiredProc := aTaskProc;
   Result := Self;
   Result := Self;
 end;
 end;
 
 
+function TScheduledTask.OnExpired_Sync(aTaskProc: TTaskProc): IScheduledTask;
+begin
+  Result := OnExpired(aTaskProc);
+  TScheduledTask(Result).ExpireWithSync := True;
+end;
+
 function TScheduledTask.OnTerminated(aTaskProc: TTaskProc): IScheduledTask;
 function TScheduledTask.OnTerminated(aTaskProc: TTaskProc): IScheduledTask;
 begin
 begin
   fTerminateProc := aTaskProc;
   fTerminateProc := aTaskProc;
   Result := Self;
   Result := Self;
 end;
 end;
 
 
+function TScheduledTask.OnTerminated_Sync(aTaskProc: TTaskProc): IScheduledTask;
+begin
+  Result := OnTerminated(aTaskProc);
+  TTask(Result).TerminateWithSync := True;
+end;
+
 { TScheduledWorker }
 { TScheduledWorker }
 
 
 constructor TScheduledWorker.Create(aNumWorker : Integer; aScheduledTask: IScheduledTask);
 constructor TScheduledWorker.Create(aNumWorker : Integer; aScheduledTask: IScheduledTask);
 begin
 begin
   inherited Create(aNumWorker,nil);
   inherited Create(aNumWorker,nil);
+  NameThreadForDebugging(aScheduledTask.Name,aScheduledTask.IdTask);
   FreeOnTerminate := True;
   FreeOnTerminate := True;
-  fTask := aScheduledTask;
+  fCurrentTask := aScheduledTask;
 end;
 end;
 
 
 procedure TScheduledWorker.Execute;
 procedure TScheduledWorker.Execute;
 begin
 begin
   fStatus := TWorkerStatus.wsIdle;
   fStatus := TWorkerStatus.wsIdle;
-  if Assigned(fTask) then
+  if Assigned(fCurrentTask) then
   begin
   begin
     try
     try
       fStatus := TWorkerStatus.wsWorking;
       fStatus := TWorkerStatus.wsWorking;
       try
       try
-        fTask.DoExecute;
+        if TTask(fCurrentTask).ExecuteWithSync then Synchronize(ExecuteTask)
+          else fCurrentTask.DoExecute;
         fStatus := TWorkerStatus.wsIdle;
         fStatus := TWorkerStatus.wsIdle;
       except
       except
         on E : Exception do
         on E : Exception do
         begin
         begin
-          if fTask <> nil then fTask.DoException(E)
+          if fCurrentTask <> nil then fCurrentTask.DoException(E)
             else raise Exception.Create(e.Message);
             else raise Exception.Create(e.Message);
         end;
         end;
       end;
       end;
     finally
     finally
-      fTask.DoTerminate;
+      if TTask(fCurrentTask).TerminateWithSync then Synchronize(TerminateTask)
+        else fCurrentTask.DoTerminate;
+      //check if expired
+      if (fCurrentTask as IScheduledTask).IsFinished then
+      begin
+        if TScheduledTask(fCurrentTask).ExpireWithSync then Synchronize(ExpireTask)
+          else (fCurrentTask as IScheduledTask).DoExpire;
+      end;
     end;
     end;
   end;
   end;
-  fTask := nil;
+  fCurrentTask := nil;
   fStatus := TWorkerStatus.wsSuspended;
   fStatus := TWorkerStatus.wsSuspended;
 end;
 end;
 
 
+procedure TScheduledWorker.ExpireTask;
+begin
+  (fCurrentTask as IScheduledTask).DoExpire;
+end;
+
 { TScheduler }
 { TScheduler }
 
 
 constructor TScheduler.Create(aTaskList : TScheduledTaskList);
 constructor TScheduler.Create(aTaskList : TScheduledTaskList);
@@ -1381,7 +1492,8 @@ begin
         begin
         begin
           if task.IsEnabled then
           if task.IsEnabled then
           begin
           begin
-            task.DoExpire;
+            //if TScheduledTask(task).ExpireWithSync then Synchronize(ExpireTask)
+            //  else task.DoExpire;
             if fRemoveTaskAfterExpiration then fTaskList.Remove(task);
             if fRemoveTaskAfterExpiration then fTaskList.Remove(task);
           end;
           end;
         end;
         end;
@@ -1394,6 +1506,11 @@ begin
   end;
   end;
 end;
 end;
 
 
+procedure TScheduler.ExpireTask;
+begin
+
+end;
+
 function TScheduler.Add(aTask: TScheduledTask): Integer;
 function TScheduler.Add(aTask: TScheduledTask): Integer;
 begin
 begin
   Result := fTaskList.Add(aTask);
   Result := fTaskList.Add(aTask);
@@ -1429,4 +1546,43 @@ begin
   end;
   end;
 end;
 end;
 
 
+{ TAdvThread }
+
+constructor TAdvThread.Create(aProc : TProc; aSynchronize : Boolean);
+begin
+  inherited Create(True);
+  FreeOnTerminate := True;
+  fExecuteWithSync := aSynchronize;
+  fExecuteProc := aProc;
+end;
+
+procedure TAdvThread.DoExecute;
+begin
+  if Assigned(fExecuteProc) then fExecuteProc;
+end;
+
+procedure TAdvThread.CallToTerminate;
+begin
+  if Assigned(fTerminateProc) then fTerminateProc;
+end;
+
+procedure TAdvThread.DoTerminate;
+begin
+  if fTerminateWithSync then Synchronize(CallToTerminate)
+    else CallToTerminate;
+end;
+
+procedure TAdvThread.Execute;
+begin
+  if fExecuteWithSync then Synchronize(DoExecute)
+    else DoExecute;
+end;
+
+
+procedure TAdvThread.OnTerminate(aProc: TProc; aSynchronize: Boolean);
+begin
+  fTerminateWithSync := aSynchronize;
+  fTerminateProc := aProc;
+end;
+
 end.
 end.

+ 8 - 2
Quick.Value.pas

@@ -7,7 +7,7 @@
   Author      : Kike Pérez
   Author      : Kike Pérez
   Version     : 1.4
   Version     : 1.4
   Created     : 07/01/2019
   Created     : 07/01/2019
-  Modified    : 15/01/2019
+  Modified    : 16/01/2019
 
 
   This file is part of QuickLib: https://github.com/exilon/QuickLib
   This file is part of QuickLib: https://github.com/exilon/QuickLib
 
 
@@ -176,7 +176,11 @@ type
 
 
   TFlexValue = record
   TFlexValue = record
   private
   private
+    {$IFNDEF FPC}
     fDataIntf : IInterface;
     fDataIntf : IInterface;
+    {$ELSE}
+    fDataIntf : TValueData;
+    {$ENDIF}
     fDataType : TValueDataType;
     fDataType : TValueDataType;
     function CastToString : string;
     function CastToString : string;
     {$IFNDEF NEXTGEN}
     {$IFNDEF NEXTGEN}
@@ -533,7 +537,9 @@ begin
     vtPointer : AsPointer := Value.VPointer;
     vtPointer : AsPointer := Value.VPointer;
     else raise Exception.Create('DataType not supported by TFlexValue');
     else raise Exception.Create('DataType not supported by TFlexValue');
   end;
   end;
-  //fDataIntf._AddRef;
+  {$IFDEF FPC}
+  fDataIntf._AddRef;
+  {$ENDIF}
 end;
 end;
 
 
 {$IFNDEF FPC}
 {$IFNDEF FPC}

+ 23 - 4
README.md

@@ -251,7 +251,12 @@ SMTP.SendMail;
 - **TThreadedQueueCS:** Version of TThreadedQueue with Critical Section.
 - **TThreadedQueueCS:** Version of TThreadedQueue with Critical Section.
 - **TThreadObjectList:** Thread safe Object List.
 - **TThreadObjectList:** Thread safe Object List.
 - **TThreadedQueueList:** Thread safe Queue List. Autogrow and with Critical Section.
 - **TThreadedQueueList:** Thread safe Queue List. Autogrow and with Critical Section.
-- **TAnonymousThread:** Creates anonymous thread defining unchained Execute and OnTerminate methods.
+- **TAnonymousThread:** Creates anonymous thread defining unchained Execute and OnTerminate methods. Use Execute_Sync and OnTerminate_Sync methods if code needs to update UI.
+  - *Execute:* Specify code to execute on start.
+  - *Execute_Sync:* Like Execute but runs code with syncronized thread method (avoids problems if your code updates UI).
+  - *OnTerminate:* Specify code to execute when task finishes.
+  - *OnTerminate_Sync:* Like OnTerminate but runs code with syncronized thread method (avoids problems if your code updates UI).
+  - *Start:* Starts thread execution.
 ```delphi
 ```delphi
 //simple anonymousthread
 //simple anonymousthread
 TAnonymousThread.Execute(
 TAnonymousThread.Execute(
@@ -270,7 +275,13 @@ TAnonymousThread.Execute(
       end)
       end)
     .Start;
     .Start;
 ```
 ```
-- **TBackgroundsTasks:** Launch tasks in background allowing number of concurrent workers.
+- **TBackgroundsTasks:** Launch tasks in background allowing number of concurrent workers. Use AddTask_Sync and OnTerminate_Sync methods if code needs to update UI.
+  - *AddTask:* Specify Task name, parameters to pass to anonymous method(If OwnedParams=true, task will free params on expiration task) and method than will be executed. 
+  - *AddTask_Sync:* Like AddTask but runs code with synchronize thread method (avoids problems if your code updates UI).
+  - *OnTerminate:* Specify code to execute when task finishes.
+  - *OnTerminate_Sync:* Like OnTerminate but runs code with syncronized thread method (avoids problems if your code updates UI).
+  - *OnException:* Specify code to execute when task generates an exception.
+  - *Start:* Starts tasks execution.
 ```delphi
 ```delphi
     backgroundtasks := TBackgroundTasks.Create(10);
     backgroundtasks := TBackgroundTasks.Create(10);
     for i := 1 to 100 do
     for i := 1 to 100 do
@@ -299,12 +310,20 @@ TAnonymousThread.Execute(
     end;
     end;
     backgroundtasks.Start;
     backgroundtasks.Start;
 ```
 ```
-- **TScheduledTasks:** Alternative to Timer. You can assign tasks with start time, repeat options and expiration date.
+- **TScheduledTasks:** Alternative to Timer. You can assign tasks with start time, repeat options and expiration date. Use AddTask_Sync, OnTerminate_Sync and OnExpired_Sync if code needs to update UI.
 You can assign anonymous methods to execute, exception, terminate and expiration events.
 You can assign anonymous methods to execute, exception, terminate and expiration events.
   - *AddTask:* Specify Task name, parameters to pass to anonymous method(If OwnedParams=true, task will free params on expiration task) and method than will be executed. 
   - *AddTask:* Specify Task name, parameters to pass to anonymous method(If OwnedParams=true, task will free params on expiration task) and method than will be executed. 
+  - *AddTask_Sync:* Like AddTask but runs code with synchronize thread method (avoids problems if your code updates UI).
+  - *OnTerminate:* Specify code to execute when task finishes.
+  - *OnTerminate_Sync:* Like OnTerminate but runs code with syncronized thread method (avoids problems if your code updates UI).
+  - *OnExpire:* Specify code to execute when task expiration reached or task was cancelled.
+  - *OnExpire_Sync:* Like OnExpire but runs code with synchronized thread method (avoids problems if your code updates UI).
+  - *OnException:* Specify code to execute when task generates an exception.
   - *StartAt:* Date and time to start task.
   - *StartAt:* Date and time to start task.
   - *RunOnce:* Task will executed only one time. If there aren't a previous StartAt, task will be executed immediately.
   - *RunOnce:* Task will executed only one time. If there aren't a previous StartAt, task will be executed immediately.
-  - *RepeatEvery:* Can indicate repeat step over time and expiration date. If not previous StartAtspecified, task will be executed immediately.
+  - *RepeatEvery:* Can indicate repeat step over time and expiration date. If not previous StartAt was specified, task will be executed immediately.
+  - *Start:* Starts scheduler.
+  - *Stop:* Stops scheduler.
 ```delphi
 ```delphi
 myjob := TMyJob.Create;
 myjob := TMyJob.Create;
 myjob.Name := Format('Run at %s and repeat every 1 second until %s',[DateTimeToStr(ScheduledDate),DateTimeToStr(ExpirationDate)]);
 myjob.Name := Format('Run at %s and repeat every 1 second until %s',[DateTimeToStr(ScheduledDate),DateTimeToStr(ExpirationDate)]);

+ 14 - 43
samples/delphi/QuickThreads/AnonymousThread/AnonymousThread.dproj

@@ -160,13 +160,24 @@
                 </Source>
                 </Source>
             </Delphi.Personality>
             </Delphi.Personality>
             <Deployment Version="3">
             <Deployment Version="3">
+                <DeployFile LocalName="$(BDS)\Redist\osx32\libcgunwind.1.0.dylib" Class="DependencyModule">
+                    <Platform Name="OSX32">
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
+                <DeployFile LocalName="Win32\Debug\AnonymousThread.exe" Configuration="Debug" Class="ProjectOutput">
+                    <Platform Name="Win32">
+                        <RemoteName>AnonymousThread.exe</RemoteName>
+                        <Overwrite>true</Overwrite>
+                    </Platform>
+                </DeployFile>
                 <DeployFile LocalName="$(BDS)\Redist\osx64\libcgsqlite3.dylib" Class="DependencyModule">
                 <DeployFile LocalName="$(BDS)\Redist\osx64\libcgsqlite3.dylib" Class="DependencyModule">
                     <Platform Name="OSX64">
                     <Platform Name="OSX64">
                         <Overwrite>true</Overwrite>
                         <Overwrite>true</Overwrite>
                     </Platform>
                     </Platform>
                 </DeployFile>
                 </DeployFile>
-                <DeployFile LocalName="$(BDS)\Redist\osx32\libcgunwind.1.0.dylib" Class="DependencyModule">
-                    <Platform Name="OSX32">
+                <DeployFile LocalName="$(BDS)\Redist\iossimulator\libPCRE.dylib" Class="DependencyModule">
+                    <Platform Name="iOSSimulator">
                         <Overwrite>true</Overwrite>
                         <Overwrite>true</Overwrite>
                     </Platform>
                     </Platform>
                 </DeployFile>
                 </DeployFile>
@@ -185,12 +196,6 @@
                         <Overwrite>true</Overwrite>
                         <Overwrite>true</Overwrite>
                     </Platform>
                     </Platform>
                 </DeployFile>
                 </DeployFile>
-                <DeployFile LocalName="Win32\Debug\AnonymousThread.exe" Configuration="Debug" Class="ProjectOutput">
-                    <Platform Name="Win32">
-                        <RemoteName>AnonymousThread.exe</RemoteName>
-                        <Overwrite>true</Overwrite>
-                    </Platform>
-                </DeployFile>
                 <DeployClass Name="AdditionalDebugSymbols">
                 <DeployClass Name="AdditionalDebugSymbols">
                     <Platform Name="iOSSimulator">
                     <Platform Name="iOSSimulator">
                         <Operation>1</Operation>
                         <Operation>1</Operation>
@@ -200,6 +205,7 @@
                         <Operation>1</Operation>
                         <Operation>1</Operation>
                     </Platform>
                     </Platform>
                     <Platform Name="Win32">
                     <Platform Name="Win32">
+                        <RemoteDir>Contents\MacOS</RemoteDir>
                         <Operation>0</Operation>
                         <Operation>0</Operation>
                     </Platform>
                     </Platform>
                 </DeployClass>
                 </DeployClass>
@@ -335,11 +341,6 @@
                         <Operation>1</Operation>
                         <Operation>1</Operation>
                         <Extensions>.framework</Extensions>
                         <Extensions>.framework</Extensions>
                     </Platform>
                     </Platform>
-                    <Platform Name="OSX64">
-                        <RemoteDir>Contents\MacOS</RemoteDir>
-                        <Operation>1</Operation>
-                        <Extensions>.framework</Extensions>
-                    </Platform>
                     <Platform Name="Win32">
                     <Platform Name="Win32">
                         <Operation>0</Operation>
                         <Operation>0</Operation>
                     </Platform>
                     </Platform>
@@ -362,11 +363,6 @@
                         <Operation>1</Operation>
                         <Operation>1</Operation>
                         <Extensions>.dylib</Extensions>
                         <Extensions>.dylib</Extensions>
                     </Platform>
                     </Platform>
-                    <Platform Name="OSX64">
-                        <RemoteDir>Contents\MacOS</RemoteDir>
-                        <Operation>1</Operation>
-                        <Extensions>.dylib</Extensions>
-                    </Platform>
                     <Platform Name="Win32">
                     <Platform Name="Win32">
                         <Operation>0</Operation>
                         <Operation>0</Operation>
                         <Extensions>.dll;.bpl</Extensions>
                         <Extensions>.dll;.bpl</Extensions>
@@ -390,11 +386,6 @@
                         <Operation>1</Operation>
                         <Operation>1</Operation>
                         <Extensions>.dylib</Extensions>
                         <Extensions>.dylib</Extensions>
                     </Platform>
                     </Platform>
-                    <Platform Name="OSX64">
-                        <RemoteDir>Contents\MacOS</RemoteDir>
-                        <Operation>1</Operation>
-                        <Extensions>.dylib</Extensions>
-                    </Platform>
                     <Platform Name="Win32">
                     <Platform Name="Win32">
                         <Operation>0</Operation>
                         <Operation>0</Operation>
                         <Extensions>.bpl</Extensions>
                         <Extensions>.bpl</Extensions>
@@ -417,10 +408,6 @@
                         <RemoteDir>Contents\Resources\StartUp\</RemoteDir>
                         <RemoteDir>Contents\Resources\StartUp\</RemoteDir>
                         <Operation>0</Operation>
                         <Operation>0</Operation>
                     </Platform>
                     </Platform>
-                    <Platform Name="OSX64">
-                        <RemoteDir>Contents\Resources\StartUp\</RemoteDir>
-                        <Operation>0</Operation>
-                    </Platform>
                     <Platform Name="Win32">
                     <Platform Name="Win32">
                         <Operation>0</Operation>
                         <Operation>0</Operation>
                     </Platform>
                     </Platform>
@@ -568,30 +555,18 @@
                         <RemoteDir>..\</RemoteDir>
                         <RemoteDir>..\</RemoteDir>
                         <Operation>1</Operation>
                         <Operation>1</Operation>
                     </Platform>
                     </Platform>
-                    <Platform Name="OSX64">
-                        <RemoteDir>..\</RemoteDir>
-                        <Operation>1</Operation>
-                    </Platform>
                 </DeployClass>
                 </DeployClass>
                 <DeployClass Name="ProjectOSXInfoPList">
                 <DeployClass Name="ProjectOSXInfoPList">
                     <Platform Name="OSX32">
                     <Platform Name="OSX32">
                         <RemoteDir>Contents</RemoteDir>
                         <RemoteDir>Contents</RemoteDir>
                         <Operation>1</Operation>
                         <Operation>1</Operation>
                     </Platform>
                     </Platform>
-                    <Platform Name="OSX64">
-                        <RemoteDir>Contents</RemoteDir>
-                        <Operation>1</Operation>
-                    </Platform>
                 </DeployClass>
                 </DeployClass>
                 <DeployClass Name="ProjectOSXResource">
                 <DeployClass Name="ProjectOSXResource">
                     <Platform Name="OSX32">
                     <Platform Name="OSX32">
                         <RemoteDir>Contents\Resources</RemoteDir>
                         <RemoteDir>Contents\Resources</RemoteDir>
                         <Operation>1</Operation>
                         <Operation>1</Operation>
                     </Platform>
                     </Platform>
-                    <Platform Name="OSX64">
-                        <RemoteDir>Contents\Resources</RemoteDir>
-                        <Operation>1</Operation>
-                    </Platform>
                 </DeployClass>
                 </DeployClass>
                 <DeployClass Required="true" Name="ProjectOutput">
                 <DeployClass Required="true" Name="ProjectOutput">
                     <Platform Name="Android">
                     <Platform Name="Android">
@@ -614,10 +589,6 @@
                         <RemoteDir>Contents\MacOS</RemoteDir>
                         <RemoteDir>Contents\MacOS</RemoteDir>
                         <Operation>1</Operation>
                         <Operation>1</Operation>
                     </Platform>
                     </Platform>
-                    <Platform Name="OSX64">
-                        <RemoteDir>Contents\MacOS</RemoteDir>
-                        <Operation>1</Operation>
-                    </Platform>
                     <Platform Name="Win32">
                     <Platform Name="Win32">
                         <Operation>0</Operation>
                         <Operation>0</Operation>
                     </Platform>
                     </Platform>

+ 6 - 6
samples/firemonkey/QuickThreads/ScheduledTasks/RunScheduledTasks.dproj

@@ -382,21 +382,21 @@
                         <Overwrite>true</Overwrite>
                         <Overwrite>true</Overwrite>
                     </Platform>
                     </Platform>
                 </DeployFile>
                 </DeployFile>
-                <DeployFile LocalName="Android\Debug\libRunScheduledTasks.so" Configuration="Debug" Class="ProjectOutput">
+                <DeployFile LocalName="$(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png" Configuration="Debug" Class="Android_SplashImage426">
                     <Platform Name="Android">
                     <Platform Name="Android">
-                        <RemoteName>libRunScheduledTasks.so</RemoteName>
+                        <RemoteName>splash_image.png</RemoteName>
                         <Overwrite>true</Overwrite>
                         <Overwrite>true</Overwrite>
                     </Platform>
                     </Platform>
                 </DeployFile>
                 </DeployFile>
-                <DeployFile LocalName="$(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png" Configuration="Debug" Class="Android_LauncherIcon144">
+                <DeployFile LocalName="Android\Debug\libRunScheduledTasks.so" Configuration="Debug" Class="ProjectOutput">
                     <Platform Name="Android">
                     <Platform Name="Android">
-                        <RemoteName>ic_launcher.png</RemoteName>
+                        <RemoteName>libRunScheduledTasks.so</RemoteName>
                         <Overwrite>true</Overwrite>
                         <Overwrite>true</Overwrite>
                     </Platform>
                     </Platform>
                 </DeployFile>
                 </DeployFile>
-                <DeployFile LocalName="$(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png" Configuration="Debug" Class="Android_SplashImage426">
+                <DeployFile LocalName="$(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png" Configuration="Debug" Class="Android_LauncherIcon144">
                     <Platform Name="Android">
                     <Platform Name="Android">
-                        <RemoteName>splash_image.png</RemoteName>
+                        <RemoteName>ic_launcher.png</RemoteName>
                         <Overwrite>true</Overwrite>
                         <Overwrite>true</Overwrite>
                     </Platform>
                     </Platform>
                 </DeployFile>
                 </DeployFile>

BIN
samples/firemonkey/QuickThreads/ScheduledTasks/RunScheduledTasks.res


+ 9 - 9
samples/firemonkey/QuickThreads/ScheduledTasks/main.pas

@@ -89,7 +89,7 @@ begin
   myjob := TMyJob.Create;
   myjob := TMyJob.Create;
     myjob.Id := 1;
     myjob.Id := 1;
     myjob.Name := 'Run now and repeat every 1 second for 5 times';
     myjob.Name := 'Run now and repeat every 1 second for 5 times';
-    scheduledtasks.AddTask('Task1',[myjob,1],True,
+    scheduledtasks.AddTask_Sync('Task1',[myjob,1],True,
                             procedure(task : ITask)
                             procedure(task : ITask)
                             begin
                             begin
                               Log('task "%s" started',[TMyJob(task.Param[0]).Name]);
                               Log('task "%s" started',[TMyJob(task.Param[0]).Name]);
@@ -100,12 +100,12 @@ begin
                             begin
                             begin
                               Log('task "%s" failed (%s)',[TMyJob(task.Param[0]).Name,aException.Message]);
                               Log('task "%s" failed (%s)',[TMyJob(task.Param[0]).Name,aException.Message]);
                             end
                             end
-                          ).OnTerminated(
+                          ).OnTerminated_Sync(
                             procedure(task : ITask)
                             procedure(task : ITask)
                             begin
                             begin
                               Log('task "%s" finished',[TMyJob(task.Param[0]).Name]);
                               Log('task "%s" finished',[TMyJob(task.Param[0]).Name]);
                             end
                             end
-                          ).OnExpired(
+                          ).OnExpired_Sync(
                             procedure(task : ITask)
                             procedure(task : ITask)
                             begin
                             begin
                               Log('task "%s" expired',[TMyJob(task.Param[0]).Name]);
                               Log('task "%s" expired',[TMyJob(task.Param[0]).Name]);
@@ -115,7 +115,7 @@ begin
     myjob := TMyJob.Create;
     myjob := TMyJob.Create;
     myjob.Id := 2;
     myjob.Id := 2;
     myjob.Name := 'Run now, repeat every 1 second forever';
     myjob.Name := 'Run now, repeat every 1 second forever';
-    scheduledtasks.AddTask('Task2',[myjob,32,true,3.2,myjob.ClassType],True,
+    scheduledtasks.AddTask_Sync('Task2',[myjob,32,true,3.2,myjob.ClassType],True,
                             procedure(task : ITask)
                             procedure(task : ITask)
                             begin
                             begin
                               Log('task "%s" started with params(Int=%d / Bool=%s / Float=%s /Class=%s)',[TMyJob(task.Param[0]).Name,task.Param[1].AsInteger,task.Param[2].AsString,task.Param[3].AsString,task.Param[4].AsString]);
                               Log('task "%s" started with params(Int=%d / Bool=%s / Float=%s /Class=%s)',[TMyJob(task.Param[0]).Name,task.Param[1].AsInteger,task.Param[2].AsString,task.Param[3].AsString,task.Param[4].AsString]);
@@ -126,12 +126,12 @@ begin
                             begin
                             begin
                               Log('task "%s" failed (%s)',[TMyJob(task.Param[0]).Name,aException.Message]);
                               Log('task "%s" failed (%s)',[TMyJob(task.Param[0]).Name,aException.Message]);
                             end
                             end
-                          ).OnTerminated(
+                          ).OnTerminated_Sync(
                             procedure(task : ITask)
                             procedure(task : ITask)
                             begin
                             begin
                               Log('task "%s" finished',[TMyJob(task.Param[0]).Name]);
                               Log('task "%s" finished',[TMyJob(task.Param[0]).Name]);
                             end
                             end
-                          ).OnExpired(
+                          ).OnExpired_Sync(
                             procedure(task : ITask)
                             procedure(task : ITask)
                             begin
                             begin
                               Log('task "%s" expired',[TMyJob(task.Param[0]).Name]);
                               Log('task "%s" expired',[TMyJob(task.Param[0]).Name]);
@@ -147,7 +147,7 @@ begin
     myjob.Name := Format('Run at %s and repeat every 1 second until %s',[DateTimeToStr(ScheduledDate),DateTimeToStr(ExpirationDate)]);
     myjob.Name := Format('Run at %s and repeat every 1 second until %s',[DateTimeToStr(ScheduledDate),DateTimeToStr(ExpirationDate)]);
 
 
 
 
-    scheduledtasks.AddTask('Task3',[myjob],True,
+    scheduledtasks.AddTask_Sync('Task3',[myjob],True,
                             procedure(task : ITask)
                             procedure(task : ITask)
                             begin
                             begin
                               Log('task "%s" started',[TMyJob(task.Param[0]).Name]);
                               Log('task "%s" started',[TMyJob(task.Param[0]).Name]);
@@ -158,12 +158,12 @@ begin
                             begin
                             begin
                               Log('task "%s" failed (%s)',[TMyJob(task.Param[0]).Name,aException.Message]);
                               Log('task "%s" failed (%s)',[TMyJob(task.Param[0]).Name,aException.Message]);
                             end
                             end
-                          ).OnTerminated(
+                          ).OnTerminated_Sync(
                             procedure(task : ITask)
                             procedure(task : ITask)
                             begin
                             begin
                               Log('task "%s" finished',[TMyJob(task.Param[0]).Name]);
                               Log('task "%s" finished',[TMyJob(task.Param[0]).Name]);
                             end
                             end
-                          ).OnExpired(
+                          ).OnExpired_Sync(
                             procedure(task : ITask)
                             procedure(task : ITask)
                             begin
                             begin
                               Log('task "%s" expired',[TMyJob(task.Param[0]).Name]);
                               Log('task "%s" expired',[TMyJob(task.Param[0]).Name]);

+ 1 - 1
samples/fpc/QuickThreads/ScheduledTasks/RunScheduledTasks.lpr

@@ -37,7 +37,7 @@ procedure TMyJob.DoJob(task : ITask);
 var
 var
   a, b, i : Integer;
   a, b, i : Integer;
 begin
 begin
-  cout('[%s] task "%s" doing a %s job...',[DateTimeToStr(Now()),fName,task.Param[0].AsString],etInfo);
+  cout('[%s] task "%s" doing a %s job %d...',[DateTimeToStr(Now()),fName,task.Param[0].AsString,task.Param[1].AsInteger],etInfo);
   Sleep(Random(1000));
   Sleep(Random(1000));
   a := Random(100);
   a := Random(100);
   b := Random(5) + 1;
   b := Random(5) + 1;