fpc/packages/vcl-compat/tests/utthreading.pp
2024-01-17 17:16:00 +01:00

1961 lines
43 KiB
ObjectPascal

unit utthreading;
{$mode objfpc}{$H+}
{$modeswitch functionreferences}
{ $DEFINE DEBUGTEST}
interface
uses
Classes, SysUtils, SyncObjs, fpcunit, testutils, testregistry, generics.collections, system.threading, system.timespan;
type
TNotifyProc = reference to procedure(Sender : TObject);
ESomeThing = Class(Exception);
{ TMyTask }
TMyTask = Class(TTask)
Function GetException : TObject;
end;
{ TLiveObject }
TLiveObject = Class(TObject)
OnDestroy : TNotifyProc;
Constructor Create(aOnDestroy : TNotifyProc); overload;
Destructor Destroy; override;
end;
{ Ex1 }
Ex1 = Class(Exception)
OnDestroy : TNotifyProc;
Id : Integer;
Constructor Create(aID : Integer; aOnDestroy : TNotifyProc); overload;
Destructor Destroy; override;
end;
Ex2 = Class(Ex1);
Ex3 = Class(Ex2);
{ TTestTExceptionList }
TTestTExceptionList = class(TTestCase)
private
FList: TExceptionList;
FEx : Array[1..3] of exception;
protected
procedure SetUp; override;
procedure TearDown; override;
published
procedure TestHookUp;
procedure TestCreate;
procedure TestAdd;
procedure TestGrow;
procedure TestClear;
procedure TestTruncate;
procedure TestGrowCapacity;
procedure TestFlatten;
procedure TestFlatten2;
procedure TestAddFromTaskNonEx;
procedure TestAddFromTaskEx;
procedure TestAddFromTaskAggEx;
end;
{ TTestAggregateException }
TTestAggregateException = Class(TTestCase)
private
class var HandleExCalledCount: Integer; // Number of times HandleEx is called.
class var HandleExNoHandleIndex: Integer; // When HandleExCalledCount=HandleExNoHandleIndex, don't set handled to true
class var HandleExRaiseErrorIndex : Integer ; // When HandleExCalledCount=HandleExRaiseErrorIndex, raise exception
private
FEx : EAggregateException;
protected
procedure SetUp; override;
procedure TearDown; override;
property Ex : EAggregateException Read FEx Write FEx;
published
procedure TestHookUp;
procedure TestAdd;
procedure TestCreateWithArray;
procedure TestCreateWithArray2;
procedure TestToString;
procedure TestHandleException1;
procedure TestHandleException2;
procedure TestHandleException3;
end;
{ TTestSparseArray }
{ TThreadedTestCase }
TThreadedTestCase = Class(TTestcase)
Public
Type
TPredicate = reference to procedure(out Done : Boolean);
{ TNotifyThread }
TNotifyThread = class(TThread)
Constructor create (aOnTerminate : TNotifyEvent); overload;
end;
Private
FTerminatedCount : Integer;
FWaitTerminatedCount: Integer;
FErrors : TStrings;
FLock : TCriticalSection;
Protected
Procedure SetUp; override;
Procedure TearDown; override;
Procedure ThreadTerminated(Sender : TObject);
procedure WaitForTerminateCount(out Done : Boolean);
Procedure AssertNoThreadErrors;
Procedure AssertThreadErrors;
Property TerminatedCount : Integer Read FTerminatedCount;
Property WaitTerminatedCount : Integer Read FWaitTerminatedCount;
Public
constructor create; override;
destructor destroy; override;
// Simple polling loop that runs until predicate returns true or timeout (in milliseconds) was reached
// Calls checksynchronize with aInterval.
// Returns true if predicate was true, false if timeout was reached.
function WaitForCondition(aPredicate : TPredicate; aTimeOut : Integer; aInterval : Integer = 10) : Boolean;
end;
TTestSparseArray = class(TThreadedTestCase)
public
Type
TSparseObjectArray = specialize TSparseArray<TObject>;
TObjectArray = Array of TObject;
TSparseThread = Class(TNotifyThread)
FList : TObjectArray;
FArray:TSparseObjectArray;
Constructor Create(aArray :TSparseObjectArray; aList : TObjectArray; aOnDestroy : TNotifyEvent);
procedure DoItem(Itm : TObject); virtual; abstract;
procedure Execute; override;
end;
{ TAddThread }
TAddThread = Class(TSparseThread)
procedure DoItem(Itm : TObject); override;
end;
{ TRemoveThread }
TRemoveThread = Class(TSparseThread)
procedure DoItem(Itm : TObject); override;
end;
private
FSparse: TSparseObjectArray;
FList1,
FList2 : TObjectArray;
protected
procedure SetUp; override;
procedure TearDown; override;
property Sparse : TSparseObjectArray Read FSparse Write FSparse;
published
procedure TestHookUp;
procedure TestAdd;
procedure TestRemove;
end;
{ TTestWorkStealingQueue }
TTestWorkStealingQueue = class(TThreadedTestCase)
protected
Type
TMyWorkQueue = specialize TWorkStealingQueue<Int64>;
TInt64DynArray = Array of Int64;
{ TWorkQueueThread }
TWorkQueueThread = Class(TNotifyThread)
FList : TInt64DynArray;
FQueue: TMyWorkQueue;
Constructor Create(aQueue : TMyWorkQueue; aList : TInt64DynArray; aOnDestroy : TNotifyEvent);
end;
{ TPushThread }
TPushThread = Class(TWorkQueueThread)
Procedure Execute; override;
end;
{ TSingleAddThread }
TSingleAddThread = Class(TNotifyThread)
FValue : Int64;
FSleep : integer;
FQueue: TMyWorkQueue;
Constructor Create(aQueue : TMyWorkQueue; aSleep : integer; aValue : Int64; aOnDestroy : TNotifyEvent);
Procedure Execute; override;
end;
{ TPopThread }
TPopThread = Class(TWorkQueueThread)
procedure Execute; override;
end;
private
FQueue: TMyWorkQueue;
protected
procedure SetUp; override;
procedure TearDown; override;
property Queue : TMyWorkQueue Read FQueue Write FQueue;
published
procedure TestHookUp;
procedure TestPush;
procedure TestPushThreaded;
procedure TestPop;
procedure TestPopThreaded;
procedure TestPopThreadedErr;
procedure TestSteal;
procedure TestStealFailTimeout;
procedure TestRemove;
procedure TestFindAndRemove;
end;
{ TCachedObject }
TCachedObject = Class(TObject)
class var _Cache : TObjectCache;
Class Function newinstance: tobject; override;
Procedure FreeInstance; override;
end;
{ TTestObjectCache }
TTestObjectCache = class(TTestCase)
private
FCache : TObjectCache;
protected
procedure ActivateCache;
procedure DeActivateCache;
procedure SetUp; override;
procedure TearDown; override;
property Cache : TObjectCache read FCache;
Published
Procedure TestHookup;
Procedure TestAdd;
Procedure TestClear;
Procedure TestRemove;
Procedure TestCreate;
end;
{ TTestObjectCaches }
TTestObjectCaches = Class(TTestCase)
private
FCaches: TObjectCaches;
protected
Procedure Setup; override;
Procedure TearDown; override;
Property Caches : TObjectCaches Read FCaches;
Published
Procedure TestHookup;
procedure TestAdd;
procedure TestGetValue;
end;
{ TTestThreading }
TTestThreading = class(TThreadedTestCase)
private
FThreadPool: TThreadPool;
FWorkCount : integer;
FWorkDone : Integer;
FThreadsTerminated : Integer;
FThreadsStarted : Integer;
procedure DoThreadStart(arg: TThread);
procedure DoThreadTerminate(arg: TThread);
procedure WaitForWorkDoneCount(out Done : Boolean);
procedure DoBurnCyclesExecute(Sender: TObject);
procedure DoSimpleExecute(Sender: TObject);
protected
procedure SetUp; override;
procedure TearDown; override;
property MyThreadPool : TThreadPool Read FThreadPool;
property WorkCount : Integer Read FWorkCount Write FWorkCount;
property WorkDone : Integer Read FWorkDone Write FWorkDone;
published
procedure TestHookUp;
procedure TestCurrentOutsideTask;
procedure TestSetMaxWorkerThreads;
procedure TestSetMinWorkerThreads;
procedure TestExecuteWork;
procedure TestExecuteLotsOfWork;
end;
{ TTestTask }
TTestTask = class(TThreadedTestCase)
private
Type
{ TTaskThread }
TTaskThread = Class(TThread)
FTask : ITask;
FSleep : Integer;
Constructor Create(aTask : ITask; aSleep : Integer);
procedure DoTask(aTask : ITask); virtual; abstract;
procedure Execute; override;
end;
{ TStartTaskThread }
TStartTaskThread = class(TTaskThread)
procedure DoTask(aTask : ITask); override;
end;
function CalcIntegerEvent(Sender: TObject): Integer;
procedure CheckTaskCanceled;
private
FTask: ITask;
FRaise : Boolean;
FWorkExecuted : Boolean;
procedure CreateTask;
procedure OnTask(Sender: TObject);
procedure StartTask;
procedure WaitForTask;
protected
procedure SetUp; override;
procedure TearDown; override;
property Task : ITask Read FTask;
Published
Procedure TestHookup;
procedure TestId;
procedure TestStatus;
Procedure TestShouldExecute;
procedure TestExecuteWork;
procedure TestExecuteWorkException;
procedure TestWaitCardinal;
procedure TestWaitTimeSpan;
procedure TestCancel;
procedure TestCheckCanceled;
procedure TestStart;
procedure TestStartTwice;
procedure TestStartException;
Procedure TestFuture;
Procedure TestFutureEvent;
end;
{ TTestParallel }
TTestParallel = Class(TThreadedTestCase)
Public
Type TResultArray = Array[1..255] of Integer;
Private
FResults : TResultArray;
class var _Results : TResultArray;
procedure CheckLocal;
procedure DoEvent(aSender: TObject; aIndex: Integer);
procedure DoEvent64(aSender: TObject; aIndex: Int64);
Protected
procedure SetUp; override;
procedure TearDown; override;
Published
Procedure TestHookup;
Procedure TestForEvent;
{$IFDEF CPU64}
Procedure TestForEvent64;
{$ENDIF}
end;
implementation
uses DateUtils;
procedure HandleEx(const aException: Exception; var aHandled: Boolean); forward;
{ TMyTask }
function TMyTask.GetException: TObject;
begin
Result:=FException;
end;
{ TLiveObject }
constructor TLiveObject.Create(aOnDestroy: TNotifyProc);
begin
OnDestroy:=aOnDestroy;
end;
destructor TLiveObject.Destroy;
begin
if assigned(OnDestroy) then
OnDestroy(Self);
inherited Destroy;
end;
{ Ex1 }
constructor Ex1.Create(aID: Integer; aOnDestroy: TNotifyProc);
begin
ID:=AID;
OnDestroy:=aOnDestroy;
end;
destructor Ex1.Destroy;
begin
if assigned(OnDestroy) then
OnDestroy(Self);
inherited Destroy;
end;
{ TTestTExceptionList }
procedure TTestTExceptionList.SetUp;
begin
inherited SetUp;
FList:=Default(TExceptionList);
FEx[1]:=Ex1.Create('ex1');
FEx[2]:=Ex2.Create('ex2');
FEx[3]:=Ex3.Create('ex3');
end;
procedure TTestTExceptionList.TearDown;
Var
I : Integer;
begin
FList:=Default(TExceptionList);
For I:=1 to 3 do
FreeAndNil(FEx[i]);
inherited TearDown;
end;
procedure TTestTExceptionList.TestHookUp;
begin
AssertTrue('List',Flist.List=nil);
AssertEquals('Count',0,Flist.Count);
AssertEquals('Capacity',0,Flist.Capacity);
end;
procedure TTestTExceptionList.TestCreate;
begin
FList:=TExceptionList.Create(10);
AssertEquals('List',10,Length(Flist.List));
AssertEquals('Count',0,Flist.Count);
AssertEquals('Capacity',10,Flist.Capacity);
end;
procedure TTestTExceptionList.TestAdd;
var
E : Exception;
begin
FList:=TExceptionList.Create(10);
E:=FEx[1];
FList.Add(E);
AssertEquals('List',10,Length(Flist.List));
AssertEquals('Count',1,Flist.Count);
AssertSame('Exc',E,Flist.list[0]);
E:=FEx[2];
FList.Add(E);
AssertEquals('List',10,Length(Flist.List));
AssertEquals('Count',2,Flist.Count);
AssertSame('Exc',E,Flist.list[1]);
end;
procedure TTestTExceptionList.TestGrow;
var
Ex : Array[1..20] of Exception;
E : Exception;
I : Integer;
begin
FList:=TExceptionList.Create(10);
For I:=1 to 20 do
Ex[I]:=Nil;
try
For I:=1 to 20 do
begin
E:=Ex1.Create('Ex'+IntToStr(i));
Ex[I]:=E;
FList.Add(E);
end;
AssertEquals('List',20,Length(Flist.List));
AssertEquals('Count',20,Flist.Count);
For I:=1 to 20 do
AssertSame('Exc'+IntToStr(i),Ex[i],Flist.list[i-1]);
finally
For I:=1 to 20 do
FreeAndNil(Ex[I]);
end;
end;
procedure TTestTExceptionList.TestClear;
var
Ex : Array[1..20] of Exception;
E : Exception;
I : Integer;
P : TNotifyProc;
procedure dodestroy (sender : tobject);
begin
Ex[(sender as Ex1).id]:=Nil;
end;
begin
P:=@DoDestroy;
Flist:=TExceptionList.Create(10);
For I:=1 to 20 do
begin
E:=Ex1.Create(i,P);
Ex[I]:=E;
FList.Add(E);
end;
Flist.ClearList;
For I:=1 to 20 do
AssertNull('Ex '+IntToStr(I),Ex[I]);
end;
procedure TTestTExceptionList.TestTruncate;
var
Ex : TExceptionArray;
I : Integer;
begin
FList:=TExceptionList.Create(10);
For I:=1 to 3 do
FList.Add(FEx[i]);
Ex:=Flist.Truncate;
AssertEquals('Length',3,Length(Ex));
For I:=1 to 3 do
AssertSame('Ex'+IntToStr(i),FList.List[i],Ex[i]);
end;
procedure TTestTExceptionList.TestGrowCapacity;
begin
FList:=TExceptionList.Create(10);
AssertEquals('Capacity before',10,FList.Capacity);
Flist.GrowCapacity(5);
AssertEquals('Capacity after smaller',10,FList.Capacity);
Flist.GrowCapacity(15);
AssertEquals('Capacity after bigger',15,FList.Capacity);
end;
procedure TTestTExceptionList.TestFlatten;
var
I : Integer;
begin
FList:=TExceptionList.Create(1);
For I:=1 to 3 do
Flist.Flatten(FEx[i]);
AssertEquals('All in list',3,FList.Count);
For I:=1 to 3 do
AssertSame('Ex'+IntToStr(i),FEx[i],FList.List[i-1]);
end;
procedure TTestTExceptionList.TestFlatten2;
var
A : EAggregateException;
I : Integer;
begin
FList:=TExceptionList.Create(1);
A:=EAggregateException.Create('a',[Fex[1],Fex[2],Fex[3]]);
try
FList.Flatten(A);
AssertEquals('Cleared A',0,A.Count);
AssertEquals('All in list',3,FList.Count);
AssertEquals('List capacity',3,FList.Capacity);
For I:=1 to 3 do
AssertSame('Ex'+IntToStr(i),FEx[i],FList.List[i-1]);
finally
A.Free;
end;
end;
procedure TTestTExceptionList.TestAddFromTaskNonEx;
var
aTask : TMyTask;
aParams : TTask.TTaskParams;
O : TLiveObject;
P : TNotifyProc;
Procedure DoDestroy(sender : TObject);
begin
if sender=o then
O:=Nil;
end;
begin
P:=@DoDestroy;
aParams:=Default(TTask.TTaskParams);
aTask:=TMyTask.Create(aParams);
try
O:=TLiveObject.Create(P);
aTask.SetExceptionObject(O);
FList.AddFromTask(aTask);
AssertNull('No more exception',aTask.GetException);
AssertEquals('Nothing added',0,FList.count);
AssertNull('Object destroyed',O);
finally
aTask.Free;
end;
end;
procedure TTestTExceptionList.TestAddFromTaskEx;
var
aTask : TMyTask;
aParams : TTask.TTaskParams;
begin
aParams:=Default(TTask.TTaskParams);
aTask:=TMyTask.Create(aParams);
try
aTask.SetExceptionObject(Fex[1]);
FList.AddFromTask(aTask);
AssertNull('No more exception',aTask.GetException);
AssertEquals('Something added',1,FList.count);
AssertSame('Correct object',Fex[1],Flist.List[0]);
finally
aTask.Free;
end;
end;
procedure TTestTExceptionList.TestAddFromTaskAggEx;
var
A : EAggregateException;
I : Integer;
aTask : TMyTask;
aParams : TTask.TTaskParams;
begin
FList:=TExceptionList.Create(1);
aTask:=Nil;
A:=EAggregateException.Create('a',[Fex[1],Fex[2],Fex[3]]);
try
aParams:=Default(TTask.TTaskParams);
aTask:=TMyTask.Create(aParams);
aTask.SetExceptionObject(A);
FList.AddFromTask(aTask);
AssertNull('No more exception',aTask.GetException);
AssertEquals('All in list',3,FList.Count);
AssertEquals('List capacity',3,FList.Capacity);
For I:=1 to 3 do
AssertSame('Ex'+IntToStr(i),FEx[i],FList.List[i-1]);
finally
aTask.Free;
end;
end;
{ TTestAggregateException }
procedure HandleEx(const aException: Exception; var aHandled: Boolean);
begin
Inc(TTestAggregateException.HandleExCalledCount);
aHandled:=TTestAggregateException.HandleExCalledCount<>TTestAggregateException.HandleExNoHandleIndex;
if (TTestAggregateException.HandleExCalledCount= TTestAggregateException.HandleExRaiseErrorIndex) then
Raise Ex1.Create('Xevious');
end;
procedure TTestAggregateException.SetUp;
begin
inherited SetUp;
FEx:=EAggregateException.Create('x');
HandleExCalledCount:=0;
HandleExNoHandleIndex:=0;
end;
procedure TTestAggregateException.TearDown;
begin
FreeAndNil(FEx);
inherited TearDown;
end;
procedure TTestAggregateException.TestHookUp;
begin
AssertNotNull('Have exception',Fex);
AssertEquals('Message','x',Fex.Message);
AssertEquals('Count',0,Fex.Count);
AssertEquals('HandleExCalledCount',0,HandleExCalledCount);
AssertEquals('HandleExNoHandleIndex',0,HandleExNoHandleIndex);
end;
procedure TTestAggregateException.TestAdd;
var
E : Ex1;
P : TNotifyProc;
Procedure DoDestroy(sender : TObject);
begin
if sender=E then
E:=Nil;
end;
begin
P:=@DoDestroy;
E:=Ex1.Create(0,P);
try
Ex.Add(E);
AssertEquals('Count',1,Ex.Count);
AssertSame('Inner',E,Ex.InnerExceptions[0]);
finally
FreeAndNil(FEx);
end;
AssertNull('Exception freed',E);
end;
procedure TTestAggregateException.TestCreateWithArray;
var
E1 : Ex1;
E2 : Ex2;
P : TNotifyProc;
Procedure DoDestroy(sender : TObject);
begin
if sender=E1 then
E1:=Nil;
if sender=E2 then
E2:=Nil;
end;
begin
FreeAndNil(Fex);
P:=@DoDestroy;
E1:=Ex1.Create(1,P);
try
E2:=Ex2.Create(2,P);
Fex:=EAggregateException.Create('X',[E1,E2]);
AssertEquals('Msg','X',Ex.Message);
AssertEquals('Count',2,Ex.Count);
AssertSame('Inner 1',E1,Ex.InnerExceptions[0]);
AssertSame('Inner 2',E2,Ex.InnerExceptions[1]);
finally
FreeAndNil(FEx);
end;
AssertNull('Exception freed',E1);
AssertNull('Exception freed',E2);
end;
procedure TTestAggregateException.TestCreateWithArray2;
var
E1 : Ex1;
E2 : Ex2;
P : TNotifyProc;
Procedure DoDestroy(sender : TObject);
begin
if sender=E1 then
E1:=Nil;
if sender=E2 then
E2:=Nil;
end;
begin
FreeAndNil(Fex);
P:=@DoDestroy;
E1:=Ex1.Create(1,P);
try
E2:=Ex2.Create(2,P);
Fex:=EAggregateException.Create([E1,E2]);
AssertEquals('Count',2,Ex.Count);
AssertSame('Inner 1',E1,Ex.InnerExceptions[0]);
AssertSame('Inner 2',E2,Ex.InnerExceptions[1]);
finally
FreeAndNil(FEx);
end;
AssertNull('Exception freed',E1);
AssertNull('Exception freed',E2);
end;
procedure TTestAggregateException.TestToString;
Const
S = 'EAggregateException: x'+sLineBreak+
'Aggregate exception for 2 exceptions'+sLineBreak+
'#0 Ex1: 1'+sLineBreak+
'#1 Ex2: 2';
begin
Ex.Add(Ex1.Create('1'));
Ex.Add(Ex2.Create('2'));
AssertEquals('ToString',S,Ex.ToString);
end;
procedure TTestAggregateException.TestHandleException1;
Var
P : TExceptionHandlerProc;
begin
P:=@HandleEx;
Ex.Add(Ex1.Create('1'));
Ex.Add(Ex2.Create('2'));
Ex.Handle(P);
AssertEquals('Handler called',2,HandleExCalledCount);
end;
procedure TTestAggregateException.TestHandleException2;
Var
P : TExceptionHandlerProc;
HaveEx : Boolean;
begin
P:=@HandleEx;
HandleExNoHandleIndex:=2;
Ex.Add(Ex1.Create('1'));
Ex.Add(Ex2.Create('2'));
HaveEx:=False;
try
Ex.Handle(P);
except
on E : EAggregateException do
HaveEx:=True;
end;
AssertTrue('Have exception',HaveEx);
AssertEquals('Handler called',2,HandleExCalledCount);
AssertEquals('Still own processed', 1, Ex.Count);
end;
procedure TTestAggregateException.TestHandleException3;
Var
P : TExceptionHandlerProc;
HaveEx : Boolean;
begin
P:=@HandleEx;
HandleExNoHandleIndex:=2;
HandleExRaiseErrorIndex:=2;
Ex.Add(Ex1.Create('1'));
Ex.Add(Ex2.Create('2'));
HaveEx:=False;
try
Ex.Handle(P);
except
on E : Ex1 do
HaveEx:=True;
end;
AssertTrue('Have exception',HaveEx);
AssertEquals('Handler called',2,HandleExCalledCount);
AssertEquals('Still own all', 2, Ex.Count);
end;
{ TThreadedTestCase }
procedure TThreadedTestCase.SetUp;
begin
inherited SetUp;
FTerminatedCount:=0;
FWaitTerminatedCount:=0;
FLock.Enter;
try
FErrors.Clear;
finally
FLock.Leave;
end;
end;
procedure TThreadedTestCase.TearDown;
begin
inherited TearDown;
end;
procedure TThreadedTestCase.ThreadTerminated(Sender: TObject);
var
O : TObject;
Error : String;
begin
AtomicIncrement(FTerminatedCount);
O:=(Sender as TThread).FatalException;
if Assigned(O) then
begin
Error:=Sender.ClassName+' : '+O.ClassName;
if (O is Exception) then
Error:=Error+'('+Exception(O).Message+')';
FLock.Enter;
try
FErrors.Add(Error)
finally
FLock.Leave;
end;
end;
end;
procedure TThreadedTestCase.WaitForTerminateCount(out Done: Boolean);
begin
Done:=(FWaitTerminatedCount>0) and (FTerminatedCount>=FWaitTerminatedCount);
{$IFDEF DEBUGTEST}
Writeln('Done:=(',FWaitTerminatedCount,'>0) and (',FTerminatedCount,'>=',FWaitTerminatedCount,') : ',Done);
{$ENDIF}
end;
procedure TThreadedTestCase.AssertNoThreadErrors;
begin
if FErrors.Count<>0 then
Fail('Unexpected thread errors:'+sLineBreak+FErrors.Text);
end;
procedure TThreadedTestCase.AssertThreadErrors;
begin
if FErrors.Count=0 then
Fail('Expected thread errors, but none were recorded');
end;
constructor TThreadedTestCase.create;
begin
inherited create;
FLock:=TCriticalSection.Create;
Flush(output);
FErrors:=TStringList.Create;
end;
destructor TThreadedTestCase.destroy;
begin
Flush(output);
FreeAndNil(FErrors);
FreeAndNil(FLock);
inherited destroy;
end;
function TThreadedTestCase.WaitForCondition(aPredicate: TPredicate; aTimeOut: Integer; aInterval: Integer): Boolean;
Var
aStart : TDateTime;
begin
aStart:=Now;
Result:=False;
Repeat
CheckSynchronize(aInterval);
aPredicate(Result);
until Result or (MilliSecondsBetween(Now,aStart)>aTimeOut);
end;
{ TThreadedTestCase.TNotifyThread }
constructor TThreadedTestCase.TNotifyThread.create(aOnTerminate: TNotifyEvent);
begin
OnTerminate:=aOnTerminate;
FreeOnTerminate:=True;
Inherited Create(False);
end;
{ TTestSparseArray }
procedure TTestSparseArray.SetUp;
var
I : Integer;
begin
inherited SetUp;
SetLength(FList1,10);
For I:=0 to Length(FList1)-1 do
FList1[I]:=Ex1.Create(I,Nil);
SetLength(FList2,10);
For I:=0 to Length(FList2)-1 do
FList2[I]:=Ex1.Create(I,Nil);
FSparse:=TSparseObjectArray.Create(5);
end;
procedure TTestSparseArray.TearDown;
var
I : Integer;
begin
For I:=0 to Length(FList1)-1 do
FreeAndNil(FList1[i]);
SetLength(FList1,0);
For I:=0 to Length(FList2)-1 do
FreeAndNil(FList2[i]);
SetLength(FList2,0);
FreeAndNil(FSparse);
inherited TearDown;
end;
procedure TTestSparseArray.TestHookUp;
begin
AssertNotNull('Have obj',Sparse);
AssertEquals('Have list 1 of objects',10,Length(FList1));
AssertEquals('Have list 2 of objects',10,Length(FList2));
end;
procedure TTestSparseArray.TestAdd;
var
I : Integer;
L : Array of TObject;
begin
FWaitTerminatedCount:=2;
TAddThread.Create(FSparse,FList1,@ThreadTerminated);
TAddThread.Create(FSparse,FList2,@ThreadTerminated);
AssertEquals('All added',True,WaitForCondition(@WaitForTerminateCount,2000));
L:=FSparse.Current;
AssertEquals('Length',20,Length(L));
end;
procedure TTestSparseArray.TestRemove;
var
I : Integer;
L : Array of TObject;
O : TObject;
begin
FWaitTerminatedCount:=2;
for O in FList1 do
FSparse.Add(O);
for O in FList2 do
FSparse.Add(O);
L:=FSparse.Current;
AssertEquals('Length',20,Length(L));
TRemoveThread.Create(FSparse,FList1,@ThreadTerminated);
TRemoveThread.Create(FSparse,FList2,@ThreadTerminated);
AssertEquals('All added',True,WaitForCondition(@WaitForTerminateCount,2000));
L:=FSparse.Current;
// Still at 20, but all nil.
AssertEquals('Length',20,Length(L));
for O in L do
AssertNull('Null',O);
end;
{ TTestSparseArray.TAddThread }
constructor TTestSparseArray.TSparseThread.Create(aArray: TSparseObjectArray; aList: TObjectArray; aOnDestroy: TNotifyEvent);
begin
{$IFDEF DEBUGTEST}
Writeln('TTestSparseArray.TSparseThread.Create');
{$ENDIF}
FArray:=aArray;
FList:=AList;
Inherited Create(aOnDestroy);
end;
procedure TTestSparseArray.TSparseThread.Execute;
var
O : TObject;
begin
{$IFDEF DEBUGTEST}
Writeln('TTestSparseArray.TSparseThread.Execute');
{$ENDIF}
For O in FList do
begin
Sleep(Random(100));
{$IFDEF DEBUGTEST}
Writeln('Handling ',O.ToString);
{$ENDIF}
DoItem(O);
if Terminated then
break;
end;
end;
procedure TTestSparseArray.TAddThread.DoItem(Itm: TObject);
begin
FArray.Add(Itm);
end;
{ TTestSparseArray.TRemoveThread }
procedure TTestSparseArray.TRemoveThread.DoItem(Itm: TObject);
begin
FArray.Remove(Itm);
end;
{ TTestWorkStealingQueue }
procedure TTestWorkStealingQueue.SetUp;
begin
inherited SetUp;
FQueue:=TMyWorkQueue.Create;
end;
procedure TTestWorkStealingQueue.TearDown;
begin
FreeAndNil(FQueue);
inherited TearDown;
end;
procedure TTestWorkStealingQueue.TestHookUp;
begin
AssertNotNull('Have queue',Queue);
AssertTrue('Queue is empty',Queue.IsEmpty);
end;
procedure TTestWorkStealingQueue.TestPush;
var
I : int64;
begin
Queue.LocalPush(1);
AssertTrue('Can pop',Queue.LocalPop(I));
AssertEquals('Correct popped',1,I);
AssertFalse('Can no longer pop',Queue.LocalPop(I));
end;
procedure TTestWorkStealingQueue.TestPushThreaded;
Var
L1,L2 : TInt64DynArray;
I : INteger;
begin
FWaitTerminatedCount:=2;
SetLength(L1,10);
For I:=1 to 10 do
L1[I-1]:=I;
SetLength(L2,10);
For I:=11 to 20 do
L2[I-11]:=I;
TPushThread.Create(FQueue,L1,@ThreadTerminated);
TPushThread.Create(FQueue,L2,@ThreadTerminated);
AssertNoThreadErrors;
AssertEquals('All added',True,WaitForCondition(@WaitForTerminateCount,6000));
AssertEquals('Length',20,FQueue.Count);
end;
procedure TTestWorkStealingQueue.TestPop;
Var
I : Integer;
IP : Int64;
begin
For I:=1 to 20 do
FQueue.LocalPush(I);
For I:=1 to 20 do
if not FQueue.LocalPop(IP) then
Fail('Failed to pop at '+IntToStr(I))
else
AssertEquals('Correct value popped at '+IntToStr(I),21-I,IP);
AssertEquals('Length',0,FQueue.Count);
end;
procedure TTestWorkStealingQueue.TestPopThreaded;
Var
I : INteger;
L2,L1 : TInt64DynArray;
begin
FWaitTerminatedCount:=2;
For I:=1 to 20 do
FQueue.LocalPush(I);
SetLength(L1,10);
SetLength(L2,10);
TPopThread.Create(FQueue,L1,@ThreadTerminated);
TPopThread.Create(FQueue,L2,@ThreadTerminated);
AssertEquals('All added',True,WaitForCondition(@WaitForTerminateCount,4000));
AssertNoThreadErrors;
AssertEquals('Length',0,FQueue.Count);
end;
procedure TTestWorkStealingQueue.TestPopThreadedErr;
Var
I : INteger;
L2,L1 : TInt64DynArray;
begin
FWaitTerminatedCount:=2;
For I:=1 to 20 do
FQueue.LocalPush(I);
SetLength(L1,20);
SetLength(L2,20);
TPopThread.Create(FQueue,L1,@ThreadTerminated);
TPopThread.Create(FQueue,L2,@ThreadTerminated);
AssertEquals('All added',True,WaitForCondition(@WaitForTerminateCount,4000));
AssertThreadErrors;
AssertEquals('Length',0,FQueue.Count);
end;
procedure TTestWorkStealingQueue.TestSteal;
var
I : Int64;
begin
FWaitTerminatedCount:=1;
TSingleAddThread.Create(FQueue,100,321,@ThreadTerminated);
AssertTrue('Can steal',FQueue.TrySteal(I,400));
AssertEquals('All added',True,WaitForCondition(@WaitForTerminateCount,4000));
AssertEquals('Correct popped',321,I);
end;
procedure TTestWorkStealingQueue.TestStealFailTimeout;
var
I : Int64;
begin
FWaitTerminatedCount:=1;
TSingleAddThread.Create(FQueue,1000,321,@ThreadTerminated);
AssertFalse('Cannot steal',FQueue.TrySteal(I,400));
AssertEquals('All added',True,WaitForCondition(@WaitForTerminateCount,4000));
end;
procedure TTestWorkStealingQueue.TestRemove;
var
I : integer;
begin
For I:=1 to 20 do
FQueue.LocalPush(I);
AssertEquals('Count before',20,FQueue.Count);
AssertTrue('Remove existing',FQueue.Remove(18));
AssertEquals('Count after',19,FQueue.Count);
AssertFalse('Remove un existing',FQueue.Remove(33));
AssertEquals('Count after 2',19,FQueue.Count);
end;
procedure TTestWorkStealingQueue.TestFindAndRemove;
var
I : integer;
begin
For I:=1 to 20 do
FQueue.LocalPush(I);
AssertEquals('Count before',20,FQueue.Count);
AssertTrue('Remove existing',FQueue.LocalFindAndRemove(18));
AssertEquals('Count after',19,FQueue.Count);
AssertFalse('Remove un existing',FQueue.LocalFindAndRemove(33));
AssertEquals('Count after 2',19,FQueue.Count);
end;
{ TTestWorkStealingQueue.TWorkQueueThread }
constructor TTestWorkStealingQueue.TWorkQueueThread.Create(aQueue: TMyWorkQueue; aList: TInt64DynArray; aOnDestroy: TNotifyEvent);
begin
FList:=aList;
FQueue:=aQueue;
Inherited Create(aOnDestroy);
end;
{ TTestWorkStealingQueue.TAddThread }
procedure TTestWorkStealingQueue.TPushThread.Execute;
var
I : Int64;
begin
For I in FList do
begin
Sleep(Random(100));
{$IFDEF DEBUGTEST}
Writeln('Pushing');
{$ENDIF}
FQueue.LocalPush(I);
end;
{$IFDEF DEBUGTEST}
Writeln('Done');
{$ENDIF}
end;
{ TTestWorkStealingQueue.TSingleAddThread }
constructor TTestWorkStealingQueue.TSingleAddThread.Create(aQueue: TMyWorkQueue; aSleep : integer; aValue: Int64; aOnDestroy: TNotifyEvent);
begin
FValue:=aValue;
FQueue:=aQueue;
FSleep:=aSleep;
Inherited Create(aOnDestroy);
end;
procedure TTestWorkStealingQueue.TSingleAddThread.Execute;
begin
Sleep(FSleep);
FQueue.LocalPush(FValue);
end;
{ TTestWorkStealingQueue.TRemoveThread }
procedure TTestWorkStealingQueue.TPopThread.Execute;
var
i : Integer;
begin
For I:=0 to Length(FList)-1 do
begin
Sleep(Random(100));
if not FQueue.LocalPop(FList[I]) then
raise Exception.CreateFmt('Failed to get item %d',[I]);
end;
end;
{ TCachedObject }
class function TCachedObject.newinstance: tobject;
var
Obj : Pointer;
begin
Result:=Nil;
if Assigned(_cache) then
begin
Obj:=_cache.Remove;
if Assigned(Obj) then
Result:=InitInstance(Obj);
end;
If Not Assigned(Result) then
Result:=inherited NewInstance;
end;
procedure TCachedObject.FreeInstance;
begin
CleanupInstance;
if Assigned(_Cache) then
if _Cache.Insert(Pointer(Self)) then
Exit;
Inherited;
end;
{ TTestObjectCache }
procedure TTestObjectCache.ActivateCache;
begin
TCachedObject._Cache:=FCache;
end;
procedure TTestObjectCache.DeActivateCache;
begin
TCachedObject._Cache:=Nil;
end;
procedure TTestObjectCache.SetUp;
begin
inherited SetUp;
FCache:=TObjectCache.Create(TCachedObject);
end;
procedure TTestObjectCache.TearDown;
begin
TCachedObject._Cache:=Nil;
FreeAndNil(FCache);
inherited TearDown;
end;
procedure TTestObjectCache.TestHookup;
begin
AssertNotNull('Have cache',Cache);
AssertNull('Cache not active',TCachedObject._Cache);
end;
procedure TTestObjectCache.TestAdd;
Var
Obj : TCachedObject;
begin
// Create without cache.
Obj:=TCachedObject.Create;
Cache.Insert(Obj);
AssertEquals('Count',1,Cache.Count);
// The memory of the object is now managed by the cache.
end;
procedure TTestObjectCache.TestClear;
Var
Obj : TCachedObject;
I : integer;
begin
// Create without cache.
For I:=1 to 10 do
begin
Obj:=TCachedObject.Create;
Cache.Insert(Obj);
end;
// The memory of the objects is now managed by the cache.
AssertEquals('Count',10,Cache.Count);
Cache.Clear;
AssertEquals('Count',0,Cache.Count);
end;
procedure TTestObjectCache.TestRemove;
Var
Obj : Array[1..10] of TCachedObject;
I : integer;
P : Pointer;
begin
// Create without cache.
For I:=1 to 10 do
begin
Obj[i]:=TCachedObject.Create;
AssertTrue('Insert '+IntToStr(I)+'OK',Cache.Insert(Obj[i]));
end;
// The memory of the objects is now managed by the cache.
AssertEquals('Count',10,Cache.Count);
For I:=1 to 10 do
begin
P:=Cache.Remove;
AssertNotNull('Got pointer',P);
// Free the memory.
FreeMem(P);
end;
AssertNull('No 11th pointer',Cache.Remove);
end;
procedure TTestObjectCache.TestCreate;
Var
Obj : Array[1..10] of TCachedObject;
I : Integer;
begin
ActivateCache;
For I:=1 to 10 do
Obj[i]:=TCachedObject.Create;
// nothing in cache yet.
AssertEquals('Count',0,Cache.Count);
For I:=1 to 10 do
FreeAndNil(Obj[i]);
// All objects should be in cache.
AssertEquals('Count',10,Cache.Count);
For I:=1 to 10 do
Obj[i]:=TCachedObject.Create;
// Pointers from cache should have been reused.
AssertEquals('Count',0,Cache.Count);
DeActivateCache;
For I:=1 to 10 do
FreeAndNil(Obj[i]);
// Cache was disabled, to object should have been freed...
AssertEquals('Count',0,Cache.Count);
end;
{ TTestObjectCaches }
procedure TTestObjectCaches.Setup;
begin
inherited Setup;
FCaches:=TObjectCaches.Create([doOwnsValues]);
end;
procedure TTestObjectCaches.TearDown;
begin
FreeAndNil(FCaches);
inherited TearDown;
end;
procedure TTestObjectCaches.TestHookup;
begin
AssertNotNull('Have caches',Caches);
end;
procedure TTestObjectCaches.TestAdd;
begin
Caches.AddObjectCache(TCachedObject);
AssertEquals('Count',1,Caches.Count);
end;
procedure TTestObjectCaches.TestGetValue;
var
C : TObjectCache;
begin
TestAdd;
AssertFalse('Get cache (nok)',Caches.TryGetValue(TComponent,C));
AssertTrue('Get cache (ok)',Caches.TryGetValue(TCachedObject,C));
AssertEquals('Count',1,Caches.Count);
end;
{ TTestThreading }
procedure TTestThreading.TestHookUp;
begin
AssertNotNull('Have Default',TThreadPool.Default);
AssertNotNull('Have current',TThreadPool.Current);
AssertNotNull('Have instance',FThreadPool);
end;
procedure TTestThreading.TestCurrentOutsideTask;
begin
AssertSame('Current is default outside task',TThreadPool.Default,TThreadPool.Current);
end;
procedure TTestThreading.TestSetMaxWorkerThreads;
var
C : Integer;
begin
C:=FThreadPool.MaxWorkerThreads;
try
AssertFalse('No zero',FThreadPool.SetMaxWorkerThreads(0));
AssertFalse('Bigger than min',FThreadPool.SetMaxWorkerThreads(FThreadPool.MinWorkerThreads));
AssertTrue('Big value',FThreadPool.SetMaxWorkerThreads(256));
finally
FThreadPool.SetMaxWorkerThreads(C);
end;
end;
procedure TTestThreading.TestSetMinWorkerThreads;
var
C : Integer;
begin
C:=FThreadPool.MinWorkerThreads;
try
AssertFalse('No negative',FThreadPool.SetMinWorkerThreads(-1));
AssertFalse('Smaller than max',FThreadPool.SetMinWorkerThreads(FThreadPool.MaxWorkerThreads+1));
AssertTrue('zero',FThreadPool.SetMinWorkerThreads(0));
finally
FThreadPool.SetMinWorkerThreads(C);
end;
end;
procedure TTestThreading.DoSimpleExecute(Sender : TObject);
begin
AssertSame('Sender',Self,Sender);
ThreadTerminated(TThread.CurrentThread); // Will reduce count
end;
procedure TTestThreading.WaitForWorkDoneCount(out Done: Boolean);
begin
Done:=(WorkCount>0) and (WorkDone>=WorkCount);
{$IFDEF DEBUGTEST}
Writeln('Done:=(',WorkCount,'>0) and (',WorkDone,'>=',WorkCount,') -> ',Done);
{$ENDIF}
end;
procedure TTestThreading.DoThreadTerminate(arg: TThread);
begin
AtomicIncrement(FThreadsTerminated);
end;
procedure TTestThreading.DoThreadStart(arg: TThread);
begin
AtomicIncrement(FThreadsStarted);
end;
procedure TTestThreading.DoBurnCyclesExecute(Sender : TObject);
var
Cycles : Integer;
I,J,K,BurnCount : Integer;
T : TDateTime;
begin
{$IFDEF DEBUGTEST}
Writeln('Thread ',TThread.CurrentThread.ThreadID,': Starting');
{$ENDIF}
AssertSame('Sender',Self,Sender);
T:=Now;
Cycles:=10+Random(2);
For I:=1 to Cycles do
begin
BurnCount:=100000*(1+Random(5));
For J:=1 to BurnCount do
if (J and 1)=1 then
K:=K+J
else
K:=K-J;
Sleep(10+Random(10));
end;
{$IFDEF DEBUGTEST}
Writeln('Thread ',TThread.CurrentThread.ThreadID,': worked milliseconds ',MillisecondsBetween(Now,T));
{$ENDIF}
// ThreadTerminated(TThread.CurrentThread); // Will reduce count
AtomicIncrement(FWorkDone);
{$IFDEF DEBUGTEST}
Writeln('Thread ',TThread.CurrentThread.ThreadID,': Work Done ',FTerminatedCount) ;
{$ENDIF}
end;
procedure TTestThreading.TestExecuteWork;
begin
FWaitTerminatedCount:=1;
FThreadPool.QueueWorkItem(Self,@DoSimpleExecute);
AssertTrue('Task executed',WaitForCondition(@WaitForTerminateCount,500));
end;
procedure TTestThreading.TestExecuteLotsOfWork;
var
i, Count : Integer;
{$IFDEF DEBUGTEST}
T : TDateTime;
{$ENDIF}
begin
Count:=TThread.ProcessorCount*2;
WorkCount:=Count;
{$IFDEF DEBUGTEST}
T:=Now;
{$ENDIF}
For I:=1 to Count do
begin
{$IFDEF DEBUGTEST}
Writeln('Main loop queueing work item ',I,'/',count);
{$ENDIF}
FThreadPool.QueueWorkItem(Self,@DoBurnCyclesExecute);
{$IFDEF DEBUGTEST}
Writeln('Main loop sleep ',I,'/',count);
{$ENDIF}
Sleep(4);
{$IFDEF DEBUGTEST}
Writeln('Main loop wake ',I,'/',count);
{$ENDIF}
end;
AssertTrue('Tasks executed',WaitForCondition(@WaitForWorkDoneCount,10000));
{$IFDEF DEBUGTEST}
Writeln('Milliseconds ',MillisecondsBetween(Now,T));
{$ENDIF}
FreeAndNil(FThreadPool);
AssertEquals('Threads all stopped',FThreadsStarted,FThreadsTerminated);
end;
procedure TTestThreading.SetUp;
begin
Inherited;
FThreadPool:=TThreadPool.Create;
FThreadPool.OnThreadStart:=@DoThreadStart;
FThreadPool.OnThreadTerminate:=@DoThreadTerminate;
FThreadsTerminated:=0;
FThreadsStarted:=0;
end;
procedure TTestThreading.TearDown;
begin
FreeAndNil(FThreadPool);
Inherited;
end;
{ TTestTask }
procedure TTestTask.OnTask(Sender : TObject);
begin
AssertSame('Sender',Self,Sender);
AssertSame('Current task',FTask,TTask.CurrentTask);
// Writeln('FTask.Status = ',FTask.Status,', current : ',TTask.CurrentTask.Status); //TTaskStatus.Running
AssertTrue('Task status',TTask.CurrentTask.Status=TTaskStatus.Running);
if FRaise then
Raise ESomeThing.Create('MrDo');
FWorkExecuted:=True;
end;
procedure TTestTask.SetUp;
begin
inherited SetUp;
CreateTask;
end;
procedure TTestTask.CreateTask;
begin
FTask:=TTask.Create(Self,@OnTask);
FWorkExecuted:=False;
FRaise:=False;
end;
procedure TTestTask.TearDown;
begin
FTask:=Nil;
inherited TearDown;
end;
procedure TTestTask.TestHookup;
begin
AssertNotNull('Have task',Task);
AssertFalse('Work not executed',FWorkExecuted);
end;
procedure TTestTask.TestId;
var
aID : Integer;
begin
aID:=Task.Id;
AssertTrue('Have ID',aID>0);
CreateTask;
AssertTrue('Have new ID',Task.ID<>aID);
end;
procedure TTestTask.TestStatus;
begin
AssertTrue('Status created',Task.Status=TTaskStatus.Created);
end;
procedure TTestTask.TestShouldExecute;
begin
AssertFalse('Should execute',Task.ShouldExecute);
end;
procedure TTestTask.TestExecuteWork;
begin
Task.ExecuteWork;
AssertTrue('Work executed',FWorkExecuted);
AssertTrue('Status',Task.Status=TTaskStatus.Completed);
end;
procedure TTestTask.TestExecuteWorkException;
begin
FRaise:=True;
Task.ExecuteWork;
AssertFalse('Work executed',FWorkExecuted);
AssertTrue('Status',Task.Status=TTaskStatus.Exception);
end;
procedure TTestTask.TestWaitCardinal;
begin
TStartTaskThread.Create(Task,200);
AssertTrue('Wait OK',Task.Wait(400));
AssertTrue('Work executed',FWorkExecuted);
end;
procedure TTestTask.TestWaitTimeSpan;
var
T: TTimespan;
begin
TStartTaskThread.Create(Task,200);
T:=TTimeSpan.Create(0,0,0,0,400);
AssertTrue('Wait OK',Task.Wait(T));
AssertTrue('Work executed',FWorkExecuted);
end;
procedure TTestTask.TestCancel;
begin
Task.Start;
AssertTrue('Status',Task.Status>=TTaskStatus.WaitingToRun);
Task.Cancel;
AssertFalse('Work executed',FWorkExecuted);
end;
procedure TTestTask.TestCheckCanceled;
begin
Task.Start;
AssertTrue('Status',Task.Status>=TTaskStatus.WaitingToRun);
Task.Cancel;
AssertException('Cancel raises',EOperationCancelled,@CheckTaskCanceled);
end;
procedure TTestTask.TestStart;
begin
Task.Start;
AssertTrue('Status',Task.Status>=TTaskStatus.WaitingToRun);
Task.Wait;
AssertTrue('Work executed',FWorkExecuted);
end;
procedure TTestTask.TestStartTwice;
begin
Task.Start;
AssertTrue('Status',Task.Status>=TTaskStatus.WaitingToRun);
Task.Wait;
AssertTrue('Work executed',FWorkExecuted);
AssertException('Cannot start twice',EInvalidOperation,@StartTask);
end;
procedure TTestTask.WaitForTask;
begin
Task.Wait;
end;
procedure TTestTask.StartTask;
begin
Task.Start;
end;
procedure TTestTask.CheckTaskCanceled;
begin
Task.CheckCanceled;
end;
procedure TTestTask.TestStartException;
begin
FRaise:=true;
Task.Start;
AssertTrue('Status',Task.Status=TTaskStatus.WaitingToRun);
AssertException('Exception',EAggregateException,@WaitForTask);
AssertFalse('Work executed',FWorkExecuted);
end;
function CalcInteger : Integer;
begin
Sleep(40);
Result:=42;
end;
procedure TTestTask.TestFuture;
begin
AssertEquals('Calc future',42,(TTask.Specialize Future<Integer>(@CalcInteger)).Value)
end;
function TTestTask.CalcIntegerEvent(Sender : TObject) : Integer;
begin
// Writeln('Here');
Sleep(40);
AssertSame('Sender',self,Sender);
Result:=43;
// Writeln('Here 2');
end;
procedure TTestTask.TestFutureEvent;
begin
AssertEquals('Calc future',43,(TTask.Specialize Future<Integer>(Self,@CalcIntegerEvent)).Value)
end;
{ TTestTask.TTaskThread }
constructor TTestTask.TTaskThread.Create(aTask: ITask; aSleep: Integer);
begin
FTask:=aTask;
FSleep:=aSleep;
FreeOnTerminate:=True;
Inherited Create(False);
end;
procedure TTestTask.TTaskThread.Execute;
var
OK : Boolean;
begin
Sleep(FSleep);
try
OK:=False;
DoTask(FTask);
OK:=True;
finally
FTask:=Nil;
// Writeln('Task done. No errors: ',OK);
end;
end;
{ TTestTask.TStartTaskThread }
procedure TTestTask.TStartTaskThread.DoTask(aTask: ITask);
begin
aTask.Start;
end;
{ TTestParallel }
procedure TTestParallel.SetUp;
begin
inherited SetUp;
FResults:=Default(TResultArray);
_Results:=Default(TResultArray);
end;
procedure TTestParallel.TearDown;
begin
inherited TearDown;
end;
procedure TTestParallel.CheckLocal;
var
I : integer;
begin
For I:=1 to 255 do
AssertEquals('Element '+IntToStr(i),I,FResults[i]);
end;
procedure TTestParallel.TestHookup;
var
I : integer;
begin
For I:=1 to 255 do
AssertEquals('Element '+IntToStr(i),0,FResults[i]);
For I:=1 to 255 do
AssertEquals('GLobal Element '+IntToStr(i),0,_Results[i]);
end;
procedure TTestParallel.DoEvent(aSender: TObject; aIndex: Integer);
begin
// Writeln(TThread.CurrentThread.ThreadID,' EventIdx ',aIndex);
Sleep(50+(10*(1+Random(5))));
FResults[aIndex]:=aIndex;
end;
procedure TTestParallel.DoEvent64(aSender: TObject; aIndex: Int64);
begin
Sleep(50+(10*(1+Random(5))));
FResults[aIndex]:=aIndex;
end;
procedure TTestParallel.TestForEvent;
var
L : TParallel.TLoopResult;
begin
L:=TParallel.&For(Self,1,1,255,@DoEvent);
AssertTrue('Correct result',L.Completed);
CheckLocal;
end;
{$IFDEF CPU64}
procedure TTestParallel.TestForEvent64;
var
L : TParallel.TLoopResult;
begin
L:=TParallel.&For(Self,1,1,255,@DoEvent64);
AssertTrue('Correct result',L.Completed);
CheckLocal;
end;
{$ENDIF}
initialization
RegisterTests([
TTestTExceptionList,
TTestAggregateException,
TTestSparseArray,
TTestWorkStealingQueue,
TTestObjectCache,
TTestObjectCaches,
TTestThreading,
TTestTask,
TTestParallel
]);
end.