utthreading.pp 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960
  1. unit utthreading;
  2. {$mode objfpc}{$H+}
  3. {$modeswitch functionreferences}
  4. { $DEFINE DEBUGTEST}
  5. interface
  6. uses
  7. Classes, SysUtils, SyncObjs, fpcunit, testutils, testregistry, generics.collections, system.threading, system.timespan;
  8. type
  9. TNotifyProc = reference to procedure(Sender : TObject);
  10. ESomeThing = Class(Exception);
  11. { TMyTask }
  12. TMyTask = Class(TTask)
  13. Function GetException : TObject;
  14. end;
  15. { TLiveObject }
  16. TLiveObject = Class(TObject)
  17. OnDestroy : TNotifyProc;
  18. Constructor Create(aOnDestroy : TNotifyProc); overload;
  19. Destructor Destroy; override;
  20. end;
  21. { Ex1 }
  22. Ex1 = Class(Exception)
  23. OnDestroy : TNotifyProc;
  24. Id : Integer;
  25. Constructor Create(aID : Integer; aOnDestroy : TNotifyProc); overload;
  26. Destructor Destroy; override;
  27. end;
  28. Ex2 = Class(Ex1);
  29. Ex3 = Class(Ex2);
  30. { TTestTExceptionList }
  31. TTestTExceptionList = class(TTestCase)
  32. private
  33. FList: TExceptionList;
  34. FEx : Array[1..3] of exception;
  35. protected
  36. procedure SetUp; override;
  37. procedure TearDown; override;
  38. published
  39. procedure TestHookUp;
  40. procedure TestCreate;
  41. procedure TestAdd;
  42. procedure TestGrow;
  43. procedure TestClear;
  44. procedure TestTruncate;
  45. procedure TestGrowCapacity;
  46. procedure TestFlatten;
  47. procedure TestFlatten2;
  48. procedure TestAddFromTaskNonEx;
  49. procedure TestAddFromTaskEx;
  50. procedure TestAddFromTaskAggEx;
  51. end;
  52. { TTestAggregateException }
  53. TTestAggregateException = Class(TTestCase)
  54. private
  55. class var HandleExCalledCount: Integer; // Number of times HandleEx is called.
  56. class var HandleExNoHandleIndex: Integer; // When HandleExCalledCount=HandleExNoHandleIndex, don't set handled to true
  57. class var HandleExRaiseErrorIndex : Integer ; // When HandleExCalledCount=HandleExRaiseErrorIndex, raise exception
  58. private
  59. FEx : EAggregateException;
  60. protected
  61. procedure SetUp; override;
  62. procedure TearDown; override;
  63. property Ex : EAggregateException Read FEx Write FEx;
  64. published
  65. procedure TestHookUp;
  66. procedure TestAdd;
  67. procedure TestCreateWithArray;
  68. procedure TestCreateWithArray2;
  69. procedure TestToString;
  70. procedure TestHandleException1;
  71. procedure TestHandleException2;
  72. procedure TestHandleException3;
  73. end;
  74. { TTestSparseArray }
  75. { TThreadedTestCase }
  76. TThreadedTestCase = Class(TTestcase)
  77. Public
  78. Type
  79. TPredicate = reference to procedure(out Done : Boolean);
  80. { TNotifyThread }
  81. TNotifyThread = class(TThread)
  82. Constructor create (aOnTerminate : TNotifyEvent); overload;
  83. end;
  84. Private
  85. FTerminatedCount : Integer;
  86. FWaitTerminatedCount: Integer;
  87. FErrors : TStrings;
  88. FLock : TCriticalSection;
  89. Protected
  90. Procedure SetUp; override;
  91. Procedure TearDown; override;
  92. Procedure ThreadTerminated(Sender : TObject);
  93. procedure WaitForTerminateCount(out Done : Boolean);
  94. Procedure AssertNoThreadErrors;
  95. Procedure AssertThreadErrors;
  96. Property TerminatedCount : Integer Read FTerminatedCount;
  97. Property WaitTerminatedCount : Integer Read FWaitTerminatedCount;
  98. Public
  99. constructor create; override;
  100. destructor destroy; override;
  101. // Simple polling loop that runs until predicate returns true or timeout (in milliseconds) was reached
  102. // Calls checksynchronize with aInterval.
  103. // Returns true if predicate was true, false if timeout was reached.
  104. function WaitForCondition(aPredicate : TPredicate; aTimeOut : Integer; aInterval : Integer = 10) : Boolean;
  105. end;
  106. TTestSparseArray = class(TThreadedTestCase)
  107. public
  108. Type
  109. TSparseObjectArray = specialize TSparseArray<TObject>;
  110. TObjectArray = Array of TObject;
  111. TSparseThread = Class(TNotifyThread)
  112. FList : TObjectArray;
  113. FArray:TSparseObjectArray;
  114. Constructor Create(aArray :TSparseObjectArray; aList : TObjectArray; aOnDestroy : TNotifyEvent);
  115. procedure DoItem(Itm : TObject); virtual; abstract;
  116. procedure Execute; override;
  117. end;
  118. { TAddThread }
  119. TAddThread = Class(TSparseThread)
  120. procedure DoItem(Itm : TObject); override;
  121. end;
  122. { TRemoveThread }
  123. TRemoveThread = Class(TSparseThread)
  124. procedure DoItem(Itm : TObject); override;
  125. end;
  126. private
  127. FSparse: TSparseObjectArray;
  128. FList1,
  129. FList2 : TObjectArray;
  130. protected
  131. procedure SetUp; override;
  132. procedure TearDown; override;
  133. property Sparse : TSparseObjectArray Read FSparse Write FSparse;
  134. published
  135. procedure TestHookUp;
  136. procedure TestAdd;
  137. procedure TestRemove;
  138. end;
  139. { TTestWorkStealingQueue }
  140. TTestWorkStealingQueue = class(TThreadedTestCase)
  141. protected
  142. Type
  143. TMyWorkQueue = specialize TWorkStealingQueue<Int64>;
  144. TInt64DynArray = Array of Int64;
  145. { TWorkQueueThread }
  146. TWorkQueueThread = Class(TNotifyThread)
  147. FList : TInt64DynArray;
  148. FQueue: TMyWorkQueue;
  149. Constructor Create(aQueue : TMyWorkQueue; aList : TInt64DynArray; aOnDestroy : TNotifyEvent);
  150. end;
  151. { TPushThread }
  152. TPushThread = Class(TWorkQueueThread)
  153. Procedure Execute; override;
  154. end;
  155. { TSingleAddThread }
  156. TSingleAddThread = Class(TNotifyThread)
  157. FValue : Int64;
  158. FSleep : integer;
  159. FQueue: TMyWorkQueue;
  160. Constructor Create(aQueue : TMyWorkQueue; aSleep : integer; aValue : Int64; aOnDestroy : TNotifyEvent);
  161. Procedure Execute; override;
  162. end;
  163. { TPopThread }
  164. TPopThread = Class(TWorkQueueThread)
  165. procedure Execute; override;
  166. end;
  167. private
  168. FQueue: TMyWorkQueue;
  169. protected
  170. procedure SetUp; override;
  171. procedure TearDown; override;
  172. property Queue : TMyWorkQueue Read FQueue Write FQueue;
  173. published
  174. procedure TestHookUp;
  175. procedure TestPush;
  176. procedure TestPushThreaded;
  177. procedure TestPop;
  178. procedure TestPopThreaded;
  179. procedure TestPopThreadedErr;
  180. procedure TestSteal;
  181. procedure TestStealFailTimeout;
  182. procedure TestRemove;
  183. procedure TestFindAndRemove;
  184. end;
  185. { TCachedObject }
  186. TCachedObject = Class(TObject)
  187. class var _Cache : TObjectCache;
  188. Class Function newinstance: tobject; override;
  189. Procedure FreeInstance; override;
  190. end;
  191. { TTestObjectCache }
  192. TTestObjectCache = class(TTestCase)
  193. private
  194. FCache : TObjectCache;
  195. protected
  196. procedure ActivateCache;
  197. procedure DeActivateCache;
  198. procedure SetUp; override;
  199. procedure TearDown; override;
  200. property Cache : TObjectCache read FCache;
  201. Published
  202. Procedure TestHookup;
  203. Procedure TestAdd;
  204. Procedure TestClear;
  205. Procedure TestRemove;
  206. Procedure TestCreate;
  207. end;
  208. { TTestObjectCaches }
  209. TTestObjectCaches = Class(TTestCase)
  210. private
  211. FCaches: TObjectCaches;
  212. protected
  213. Procedure Setup; override;
  214. Procedure TearDown; override;
  215. Property Caches : TObjectCaches Read FCaches;
  216. Published
  217. Procedure TestHookup;
  218. procedure TestAdd;
  219. procedure TestGetValue;
  220. end;
  221. { TTestThreading }
  222. TTestThreading = class(TThreadedTestCase)
  223. private
  224. FThreadPool: TThreadPool;
  225. FWorkCount : integer;
  226. FWorkDone : Integer;
  227. FThreadsTerminated : Integer;
  228. FThreadsStarted : Integer;
  229. procedure DoThreadStart(arg: TThread);
  230. procedure DoThreadTerminate(arg: TThread);
  231. procedure WaitForWorkDoneCount(out Done : Boolean);
  232. procedure DoBurnCyclesExecute(Sender: TObject);
  233. procedure DoSimpleExecute(Sender: TObject);
  234. protected
  235. procedure SetUp; override;
  236. procedure TearDown; override;
  237. property MyThreadPool : TThreadPool Read FThreadPool;
  238. property WorkCount : Integer Read FWorkCount Write FWorkCount;
  239. property WorkDone : Integer Read FWorkDone Write FWorkDone;
  240. published
  241. procedure TestHookUp;
  242. procedure TestCurrentOutsideTask;
  243. procedure TestSetMaxWorkerThreads;
  244. procedure TestSetMinWorkerThreads;
  245. procedure TestExecuteWork;
  246. procedure TestExecuteLotsOfWork;
  247. end;
  248. { TTestTask }
  249. TTestTask = class(TThreadedTestCase)
  250. private
  251. Type
  252. { TTaskThread }
  253. TTaskThread = Class(TThread)
  254. FTask : ITask;
  255. FSleep : Integer;
  256. Constructor Create(aTask : ITask; aSleep : Integer);
  257. procedure DoTask(aTask : ITask); virtual; abstract;
  258. procedure Execute; override;
  259. end;
  260. { TStartTaskThread }
  261. TStartTaskThread = class(TTaskThread)
  262. procedure DoTask(aTask : ITask); override;
  263. end;
  264. function CalcIntegerEvent(Sender: TObject): Integer;
  265. procedure CheckTaskCanceled;
  266. private
  267. FTask: ITask;
  268. FRaise : Boolean;
  269. FWorkExecuted : Boolean;
  270. procedure CreateTask;
  271. procedure OnTask(Sender: TObject);
  272. procedure StartTask;
  273. procedure WaitForTask;
  274. protected
  275. procedure SetUp; override;
  276. procedure TearDown; override;
  277. property Task : ITask Read FTask;
  278. Published
  279. Procedure TestHookup;
  280. procedure TestId;
  281. procedure TestStatus;
  282. Procedure TestShouldExecute;
  283. procedure TestExecuteWork;
  284. procedure TestExecuteWorkException;
  285. procedure TestWaitCardinal;
  286. procedure TestWaitTimeSpan;
  287. procedure TestCancel;
  288. procedure TestCheckCanceled;
  289. procedure TestStart;
  290. procedure TestStartTwice;
  291. procedure TestStartException;
  292. Procedure TestFuture;
  293. Procedure TestFutureEvent;
  294. end;
  295. { TTestParallel }
  296. TTestParallel = Class(TThreadedTestCase)
  297. Public
  298. Type TResultArray = Array[1..255] of Integer;
  299. Private
  300. FResults : TResultArray;
  301. class var _Results : TResultArray;
  302. procedure CheckLocal;
  303. procedure DoEvent(aSender: TObject; aIndex: Integer);
  304. procedure DoEvent64(aSender: TObject; aIndex: Int64);
  305. Protected
  306. procedure SetUp; override;
  307. procedure TearDown; override;
  308. Published
  309. Procedure TestHookup;
  310. Procedure TestForEvent;
  311. {$IFDEF CPU64}
  312. Procedure TestForEvent64;
  313. {$ENDIF}
  314. end;
  315. implementation
  316. uses DateUtils;
  317. procedure HandleEx(const aException: Exception; var aHandled: Boolean); forward;
  318. { TMyTask }
  319. function TMyTask.GetException: TObject;
  320. begin
  321. Result:=FException;
  322. end;
  323. { TLiveObject }
  324. constructor TLiveObject.Create(aOnDestroy: TNotifyProc);
  325. begin
  326. OnDestroy:=aOnDestroy;
  327. end;
  328. destructor TLiveObject.Destroy;
  329. begin
  330. if assigned(OnDestroy) then
  331. OnDestroy(Self);
  332. inherited Destroy;
  333. end;
  334. { Ex1 }
  335. constructor Ex1.Create(aID: Integer; aOnDestroy: TNotifyProc);
  336. begin
  337. ID:=AID;
  338. OnDestroy:=aOnDestroy;
  339. end;
  340. destructor Ex1.Destroy;
  341. begin
  342. if assigned(OnDestroy) then
  343. OnDestroy(Self);
  344. inherited Destroy;
  345. end;
  346. { TTestTExceptionList }
  347. procedure TTestTExceptionList.SetUp;
  348. begin
  349. inherited SetUp;
  350. FList:=Default(TExceptionList);
  351. FEx[1]:=Ex1.Create('ex1');
  352. FEx[2]:=Ex2.Create('ex2');
  353. FEx[3]:=Ex3.Create('ex3');
  354. end;
  355. procedure TTestTExceptionList.TearDown;
  356. Var
  357. I : Integer;
  358. begin
  359. FList:=Default(TExceptionList);
  360. For I:=1 to 3 do
  361. FreeAndNil(FEx[i]);
  362. inherited TearDown;
  363. end;
  364. procedure TTestTExceptionList.TestHookUp;
  365. begin
  366. AssertTrue('List',Flist.List=nil);
  367. AssertEquals('Count',0,Flist.Count);
  368. AssertEquals('Capacity',0,Flist.Capacity);
  369. end;
  370. procedure TTestTExceptionList.TestCreate;
  371. begin
  372. FList:=TExceptionList.Create(10);
  373. AssertEquals('List',10,Length(Flist.List));
  374. AssertEquals('Count',0,Flist.Count);
  375. AssertEquals('Capacity',10,Flist.Capacity);
  376. end;
  377. procedure TTestTExceptionList.TestAdd;
  378. var
  379. E : Exception;
  380. begin
  381. FList:=TExceptionList.Create(10);
  382. E:=FEx[1];
  383. FList.Add(E);
  384. AssertEquals('List',10,Length(Flist.List));
  385. AssertEquals('Count',1,Flist.Count);
  386. AssertSame('Exc',E,Flist.list[0]);
  387. E:=FEx[2];
  388. FList.Add(E);
  389. AssertEquals('List',10,Length(Flist.List));
  390. AssertEquals('Count',2,Flist.Count);
  391. AssertSame('Exc',E,Flist.list[1]);
  392. end;
  393. procedure TTestTExceptionList.TestGrow;
  394. var
  395. Ex : Array[1..20] of Exception;
  396. E : Exception;
  397. I : Integer;
  398. begin
  399. FList:=TExceptionList.Create(10);
  400. For I:=1 to 20 do
  401. Ex[I]:=Nil;
  402. try
  403. For I:=1 to 20 do
  404. begin
  405. E:=Ex1.Create('Ex'+IntToStr(i));
  406. Ex[I]:=E;
  407. FList.Add(E);
  408. end;
  409. AssertEquals('List',20,Length(Flist.List));
  410. AssertEquals('Count',20,Flist.Count);
  411. For I:=1 to 20 do
  412. AssertSame('Exc'+IntToStr(i),Ex[i],Flist.list[i-1]);
  413. finally
  414. For I:=1 to 20 do
  415. FreeAndNil(Ex[I]);
  416. end;
  417. end;
  418. procedure TTestTExceptionList.TestClear;
  419. var
  420. Ex : Array[1..20] of Exception;
  421. E : Exception;
  422. I : Integer;
  423. P : TNotifyProc;
  424. procedure dodestroy (sender : tobject);
  425. begin
  426. Ex[(sender as Ex1).id]:=Nil;
  427. end;
  428. begin
  429. P:=@DoDestroy;
  430. Flist:=TExceptionList.Create(10);
  431. For I:=1 to 20 do
  432. begin
  433. E:=Ex1.Create(i,P);
  434. Ex[I]:=E;
  435. FList.Add(E);
  436. end;
  437. Flist.ClearList;
  438. For I:=1 to 20 do
  439. AssertNull('Ex '+IntToStr(I),Ex[I]);
  440. end;
  441. procedure TTestTExceptionList.TestTruncate;
  442. var
  443. Ex : TExceptionArray;
  444. I : Integer;
  445. begin
  446. FList:=TExceptionList.Create(10);
  447. For I:=1 to 3 do
  448. FList.Add(FEx[i]);
  449. Ex:=Flist.Truncate;
  450. AssertEquals('Length',3,Length(Ex));
  451. For I:=1 to 3 do
  452. AssertSame('Ex'+IntToStr(i),FList.List[i],Ex[i]);
  453. end;
  454. procedure TTestTExceptionList.TestGrowCapacity;
  455. begin
  456. FList:=TExceptionList.Create(10);
  457. AssertEquals('Capacity before',10,FList.Capacity);
  458. Flist.GrowCapacity(5);
  459. AssertEquals('Capacity after smaller',10,FList.Capacity);
  460. Flist.GrowCapacity(15);
  461. AssertEquals('Capacity after bigger',15,FList.Capacity);
  462. end;
  463. procedure TTestTExceptionList.TestFlatten;
  464. var
  465. I : Integer;
  466. begin
  467. FList:=TExceptionList.Create(1);
  468. For I:=1 to 3 do
  469. Flist.Flatten(FEx[i]);
  470. AssertEquals('All in list',3,FList.Count);
  471. For I:=1 to 3 do
  472. AssertSame('Ex'+IntToStr(i),FEx[i],FList.List[i-1]);
  473. end;
  474. procedure TTestTExceptionList.TestFlatten2;
  475. var
  476. A : EAggregateException;
  477. I : Integer;
  478. begin
  479. FList:=TExceptionList.Create(1);
  480. A:=EAggregateException.Create('a',[Fex[1],Fex[2],Fex[3]]);
  481. try
  482. FList.Flatten(A);
  483. AssertEquals('Cleared A',0,A.Count);
  484. AssertEquals('All in list',3,FList.Count);
  485. AssertEquals('List capacity',3,FList.Capacity);
  486. For I:=1 to 3 do
  487. AssertSame('Ex'+IntToStr(i),FEx[i],FList.List[i-1]);
  488. finally
  489. A.Free;
  490. end;
  491. end;
  492. procedure TTestTExceptionList.TestAddFromTaskNonEx;
  493. var
  494. aTask : TMyTask;
  495. aParams : TTask.TTaskParams;
  496. O : TLiveObject;
  497. P : TNotifyProc;
  498. Procedure DoDestroy(sender : TObject);
  499. begin
  500. if sender=o then
  501. O:=Nil;
  502. end;
  503. begin
  504. P:=@DoDestroy;
  505. aParams:=Default(TTask.TTaskParams);
  506. aTask:=TMyTask.Create(aParams);
  507. try
  508. O:=TLiveObject.Create(P);
  509. aTask.SetExceptionObject(O);
  510. FList.AddFromTask(aTask);
  511. AssertNull('No more exception',aTask.GetException);
  512. AssertEquals('Nothing added',0,FList.count);
  513. AssertNull('Object destroyed',O);
  514. finally
  515. aTask.Free;
  516. end;
  517. end;
  518. procedure TTestTExceptionList.TestAddFromTaskEx;
  519. var
  520. aTask : TMyTask;
  521. aParams : TTask.TTaskParams;
  522. begin
  523. aParams:=Default(TTask.TTaskParams);
  524. aTask:=TMyTask.Create(aParams);
  525. try
  526. aTask.SetExceptionObject(Fex[1]);
  527. FList.AddFromTask(aTask);
  528. AssertNull('No more exception',aTask.GetException);
  529. AssertEquals('Something added',1,FList.count);
  530. AssertSame('Correct object',Fex[1],Flist.List[0]);
  531. finally
  532. aTask.Free;
  533. end;
  534. end;
  535. procedure TTestTExceptionList.TestAddFromTaskAggEx;
  536. var
  537. A : EAggregateException;
  538. I : Integer;
  539. aTask : TMyTask;
  540. aParams : TTask.TTaskParams;
  541. begin
  542. FList:=TExceptionList.Create(1);
  543. aTask:=Nil;
  544. A:=EAggregateException.Create('a',[Fex[1],Fex[2],Fex[3]]);
  545. try
  546. aParams:=Default(TTask.TTaskParams);
  547. aTask:=TMyTask.Create(aParams);
  548. aTask.SetExceptionObject(A);
  549. FList.AddFromTask(aTask);
  550. AssertNull('No more exception',aTask.GetException);
  551. AssertEquals('All in list',3,FList.Count);
  552. AssertEquals('List capacity',3,FList.Capacity);
  553. For I:=1 to 3 do
  554. AssertSame('Ex'+IntToStr(i),FEx[i],FList.List[i-1]);
  555. finally
  556. aTask.Free;
  557. end;
  558. end;
  559. { TTestAggregateException }
  560. procedure HandleEx(const aException: Exception; var aHandled: Boolean);
  561. begin
  562. Inc(TTestAggregateException.HandleExCalledCount);
  563. aHandled:=TTestAggregateException.HandleExCalledCount<>TTestAggregateException.HandleExNoHandleIndex;
  564. if (TTestAggregateException.HandleExCalledCount= TTestAggregateException.HandleExRaiseErrorIndex) then
  565. Raise Ex1.Create('Xevious');
  566. end;
  567. procedure TTestAggregateException.SetUp;
  568. begin
  569. inherited SetUp;
  570. FEx:=EAggregateException.Create('x');
  571. HandleExCalledCount:=0;
  572. HandleExNoHandleIndex:=0;
  573. end;
  574. procedure TTestAggregateException.TearDown;
  575. begin
  576. FreeAndNil(FEx);
  577. inherited TearDown;
  578. end;
  579. procedure TTestAggregateException.TestHookUp;
  580. begin
  581. AssertNotNull('Have exception',Fex);
  582. AssertEquals('Message','x',Fex.Message);
  583. AssertEquals('Count',0,Fex.Count);
  584. AssertEquals('HandleExCalledCount',0,HandleExCalledCount);
  585. AssertEquals('HandleExNoHandleIndex',0,HandleExNoHandleIndex);
  586. end;
  587. procedure TTestAggregateException.TestAdd;
  588. var
  589. E : Ex1;
  590. P : TNotifyProc;
  591. Procedure DoDestroy(sender : TObject);
  592. begin
  593. if sender=E then
  594. E:=Nil;
  595. end;
  596. begin
  597. P:=@DoDestroy;
  598. E:=Ex1.Create(0,P);
  599. try
  600. Ex.Add(E);
  601. AssertEquals('Count',1,Ex.Count);
  602. AssertSame('Inner',E,Ex.InnerExceptions[0]);
  603. finally
  604. FreeAndNil(FEx);
  605. end;
  606. AssertNull('Exception freed',E);
  607. end;
  608. procedure TTestAggregateException.TestCreateWithArray;
  609. var
  610. E1 : Ex1;
  611. E2 : Ex2;
  612. P : TNotifyProc;
  613. Procedure DoDestroy(sender : TObject);
  614. begin
  615. if sender=E1 then
  616. E1:=Nil;
  617. if sender=E2 then
  618. E2:=Nil;
  619. end;
  620. begin
  621. FreeAndNil(Fex);
  622. P:=@DoDestroy;
  623. E1:=Ex1.Create(1,P);
  624. try
  625. E2:=Ex2.Create(2,P);
  626. Fex:=EAggregateException.Create('X',[E1,E2]);
  627. AssertEquals('Msg','X',Ex.Message);
  628. AssertEquals('Count',2,Ex.Count);
  629. AssertSame('Inner 1',E1,Ex.InnerExceptions[0]);
  630. AssertSame('Inner 2',E2,Ex.InnerExceptions[1]);
  631. finally
  632. FreeAndNil(FEx);
  633. end;
  634. AssertNull('Exception freed',E1);
  635. AssertNull('Exception freed',E2);
  636. end;
  637. procedure TTestAggregateException.TestCreateWithArray2;
  638. var
  639. E1 : Ex1;
  640. E2 : Ex2;
  641. P : TNotifyProc;
  642. Procedure DoDestroy(sender : TObject);
  643. begin
  644. if sender=E1 then
  645. E1:=Nil;
  646. if sender=E2 then
  647. E2:=Nil;
  648. end;
  649. begin
  650. FreeAndNil(Fex);
  651. P:=@DoDestroy;
  652. E1:=Ex1.Create(1,P);
  653. try
  654. E2:=Ex2.Create(2,P);
  655. Fex:=EAggregateException.Create([E1,E2]);
  656. AssertEquals('Count',2,Ex.Count);
  657. AssertSame('Inner 1',E1,Ex.InnerExceptions[0]);
  658. AssertSame('Inner 2',E2,Ex.InnerExceptions[1]);
  659. finally
  660. FreeAndNil(FEx);
  661. end;
  662. AssertNull('Exception freed',E1);
  663. AssertNull('Exception freed',E2);
  664. end;
  665. procedure TTestAggregateException.TestToString;
  666. Const
  667. S = 'EAggregateException: x'+sLineBreak+
  668. 'Aggregate exception for 2 exceptions'+sLineBreak+
  669. '#0 Ex1: 1'+sLineBreak+
  670. '#1 Ex2: 2';
  671. begin
  672. Ex.Add(Ex1.Create('1'));
  673. Ex.Add(Ex2.Create('2'));
  674. AssertEquals('ToString',S,Ex.ToString);
  675. end;
  676. procedure TTestAggregateException.TestHandleException1;
  677. Var
  678. P : TExceptionHandlerProc;
  679. begin
  680. P:=@HandleEx;
  681. Ex.Add(Ex1.Create('1'));
  682. Ex.Add(Ex2.Create('2'));
  683. Ex.Handle(P);
  684. AssertEquals('Handler called',2,HandleExCalledCount);
  685. end;
  686. procedure TTestAggregateException.TestHandleException2;
  687. Var
  688. P : TExceptionHandlerProc;
  689. HaveEx : Boolean;
  690. begin
  691. P:=@HandleEx;
  692. HandleExNoHandleIndex:=2;
  693. Ex.Add(Ex1.Create('1'));
  694. Ex.Add(Ex2.Create('2'));
  695. HaveEx:=False;
  696. try
  697. Ex.Handle(P);
  698. except
  699. on E : EAggregateException do
  700. HaveEx:=True;
  701. end;
  702. AssertTrue('Have exception',HaveEx);
  703. AssertEquals('Handler called',2,HandleExCalledCount);
  704. AssertEquals('Still own processed', 1, Ex.Count);
  705. end;
  706. procedure TTestAggregateException.TestHandleException3;
  707. Var
  708. P : TExceptionHandlerProc;
  709. HaveEx : Boolean;
  710. begin
  711. P:=@HandleEx;
  712. HandleExNoHandleIndex:=2;
  713. HandleExRaiseErrorIndex:=2;
  714. Ex.Add(Ex1.Create('1'));
  715. Ex.Add(Ex2.Create('2'));
  716. HaveEx:=False;
  717. try
  718. Ex.Handle(P);
  719. except
  720. on E : Ex1 do
  721. HaveEx:=True;
  722. end;
  723. AssertTrue('Have exception',HaveEx);
  724. AssertEquals('Handler called',2,HandleExCalledCount);
  725. AssertEquals('Still own all', 2, Ex.Count);
  726. end;
  727. { TThreadedTestCase }
  728. procedure TThreadedTestCase.SetUp;
  729. begin
  730. inherited SetUp;
  731. FTerminatedCount:=0;
  732. FWaitTerminatedCount:=0;
  733. FLock.Enter;
  734. try
  735. FErrors.Clear;
  736. finally
  737. FLock.Leave;
  738. end;
  739. end;
  740. procedure TThreadedTestCase.TearDown;
  741. begin
  742. inherited TearDown;
  743. end;
  744. procedure TThreadedTestCase.ThreadTerminated(Sender: TObject);
  745. var
  746. O : TObject;
  747. Error : String;
  748. begin
  749. AtomicIncrement(FTerminatedCount);
  750. O:=(Sender as TThread).FatalException;
  751. if Assigned(O) then
  752. begin
  753. Error:=Sender.ClassName+' : '+O.ClassName;
  754. if (O is Exception) then
  755. Error:=Error+'('+Exception(O).Message+')';
  756. FLock.Enter;
  757. try
  758. FErrors.Add(Error)
  759. finally
  760. FLock.Leave;
  761. end;
  762. end;
  763. end;
  764. procedure TThreadedTestCase.WaitForTerminateCount(out Done: Boolean);
  765. begin
  766. Done:=(FWaitTerminatedCount>0) and (FTerminatedCount>=FWaitTerminatedCount);
  767. {$IFDEF DEBUGTEST}
  768. Writeln('Done:=(',FWaitTerminatedCount,'>0) and (',FTerminatedCount,'>=',FWaitTerminatedCount,') : ',Done);
  769. {$ENDIF}
  770. end;
  771. procedure TThreadedTestCase.AssertNoThreadErrors;
  772. begin
  773. if FErrors.Count<>0 then
  774. Fail('Unexpected thread errors:'+sLineBreak+FErrors.Text);
  775. end;
  776. procedure TThreadedTestCase.AssertThreadErrors;
  777. begin
  778. if FErrors.Count=0 then
  779. Fail('Expected thread errors, but none were recorded');
  780. end;
  781. constructor TThreadedTestCase.create;
  782. begin
  783. inherited create;
  784. FLock:=TCriticalSection.Create;
  785. Flush(output);
  786. FErrors:=TStringList.Create;
  787. end;
  788. destructor TThreadedTestCase.destroy;
  789. begin
  790. Flush(output);
  791. FreeAndNil(FErrors);
  792. FreeAndNil(FLock);
  793. inherited destroy;
  794. end;
  795. function TThreadedTestCase.WaitForCondition(aPredicate: TPredicate; aTimeOut: Integer; aInterval: Integer): Boolean;
  796. Var
  797. aStart : TDateTime;
  798. begin
  799. aStart:=Now;
  800. Result:=False;
  801. Repeat
  802. CheckSynchronize(aInterval);
  803. aPredicate(Result);
  804. until Result or (MilliSecondsBetween(Now,aStart)>aTimeOut);
  805. end;
  806. { TThreadedTestCase.TNotifyThread }
  807. constructor TThreadedTestCase.TNotifyThread.create(aOnTerminate: TNotifyEvent);
  808. begin
  809. OnTerminate:=aOnTerminate;
  810. FreeOnTerminate:=True;
  811. Inherited Create(False);
  812. end;
  813. { TTestSparseArray }
  814. procedure TTestSparseArray.SetUp;
  815. var
  816. I : Integer;
  817. begin
  818. inherited SetUp;
  819. SetLength(FList1,10);
  820. For I:=0 to Length(FList1)-1 do
  821. FList1[I]:=Ex1.Create(I,Nil);
  822. SetLength(FList2,10);
  823. For I:=0 to Length(FList2)-1 do
  824. FList2[I]:=Ex1.Create(I,Nil);
  825. FSparse:=TSparseObjectArray.Create(5);
  826. end;
  827. procedure TTestSparseArray.TearDown;
  828. var
  829. I : Integer;
  830. begin
  831. For I:=0 to Length(FList1)-1 do
  832. FreeAndNil(FList1[i]);
  833. SetLength(FList1,0);
  834. For I:=0 to Length(FList2)-1 do
  835. FreeAndNil(FList2[i]);
  836. SetLength(FList2,0);
  837. FreeAndNil(FSparse);
  838. inherited TearDown;
  839. end;
  840. procedure TTestSparseArray.TestHookUp;
  841. begin
  842. AssertNotNull('Have obj',Sparse);
  843. AssertEquals('Have list 1 of objects',10,Length(FList1));
  844. AssertEquals('Have list 2 of objects',10,Length(FList2));
  845. end;
  846. procedure TTestSparseArray.TestAdd;
  847. var
  848. I : Integer;
  849. L : Array of TObject;
  850. begin
  851. FWaitTerminatedCount:=2;
  852. TAddThread.Create(FSparse,FList1,@ThreadTerminated);
  853. TAddThread.Create(FSparse,FList2,@ThreadTerminated);
  854. AssertEquals('All added',True,WaitForCondition(@WaitForTerminateCount,2000));
  855. L:=FSparse.Current;
  856. AssertEquals('Length',20,Length(L));
  857. end;
  858. procedure TTestSparseArray.TestRemove;
  859. var
  860. I : Integer;
  861. L : Array of TObject;
  862. O : TObject;
  863. begin
  864. FWaitTerminatedCount:=2;
  865. for O in FList1 do
  866. FSparse.Add(O);
  867. for O in FList2 do
  868. FSparse.Add(O);
  869. L:=FSparse.Current;
  870. AssertEquals('Length',20,Length(L));
  871. TRemoveThread.Create(FSparse,FList1,@ThreadTerminated);
  872. TRemoveThread.Create(FSparse,FList2,@ThreadTerminated);
  873. AssertEquals('All added',True,WaitForCondition(@WaitForTerminateCount,2000));
  874. L:=FSparse.Current;
  875. // Still at 20, but all nil.
  876. AssertEquals('Length',20,Length(L));
  877. for O in L do
  878. AssertNull('Null',O);
  879. end;
  880. { TTestSparseArray.TAddThread }
  881. constructor TTestSparseArray.TSparseThread.Create(aArray: TSparseObjectArray; aList: TObjectArray; aOnDestroy: TNotifyEvent);
  882. begin
  883. {$IFDEF DEBUGTEST}
  884. Writeln('TTestSparseArray.TSparseThread.Create');
  885. {$ENDIF}
  886. FArray:=aArray;
  887. FList:=AList;
  888. Inherited Create(aOnDestroy);
  889. end;
  890. procedure TTestSparseArray.TSparseThread.Execute;
  891. var
  892. O : TObject;
  893. begin
  894. {$IFDEF DEBUGTEST}
  895. Writeln('TTestSparseArray.TSparseThread.Execute');
  896. {$ENDIF}
  897. For O in FList do
  898. begin
  899. Sleep(Random(100));
  900. {$IFDEF DEBUGTEST}
  901. Writeln('Handling ',O.ToString);
  902. {$ENDIF}
  903. DoItem(O);
  904. if Terminated then
  905. break;
  906. end;
  907. end;
  908. procedure TTestSparseArray.TAddThread.DoItem(Itm: TObject);
  909. begin
  910. FArray.Add(Itm);
  911. end;
  912. { TTestSparseArray.TRemoveThread }
  913. procedure TTestSparseArray.TRemoveThread.DoItem(Itm: TObject);
  914. begin
  915. FArray.Remove(Itm);
  916. end;
  917. { TTestWorkStealingQueue }
  918. procedure TTestWorkStealingQueue.SetUp;
  919. begin
  920. inherited SetUp;
  921. FQueue:=TMyWorkQueue.Create;
  922. end;
  923. procedure TTestWorkStealingQueue.TearDown;
  924. begin
  925. FreeAndNil(FQueue);
  926. inherited TearDown;
  927. end;
  928. procedure TTestWorkStealingQueue.TestHookUp;
  929. begin
  930. AssertNotNull('Have queue',Queue);
  931. AssertTrue('Queue is empty',Queue.IsEmpty);
  932. end;
  933. procedure TTestWorkStealingQueue.TestPush;
  934. var
  935. I : int64;
  936. begin
  937. Queue.LocalPush(1);
  938. AssertTrue('Can pop',Queue.LocalPop(I));
  939. AssertEquals('Correct popped',1,I);
  940. AssertFalse('Can no longer pop',Queue.LocalPop(I));
  941. end;
  942. procedure TTestWorkStealingQueue.TestPushThreaded;
  943. Var
  944. L1,L2 : TInt64DynArray;
  945. I : INteger;
  946. begin
  947. FWaitTerminatedCount:=2;
  948. SetLength(L1,10);
  949. For I:=1 to 10 do
  950. L1[I-1]:=I;
  951. SetLength(L2,10);
  952. For I:=11 to 20 do
  953. L2[I-11]:=I;
  954. TPushThread.Create(FQueue,L1,@ThreadTerminated);
  955. TPushThread.Create(FQueue,L2,@ThreadTerminated);
  956. AssertNoThreadErrors;
  957. AssertEquals('All added',True,WaitForCondition(@WaitForTerminateCount,6000));
  958. AssertEquals('Length',20,FQueue.Count);
  959. end;
  960. procedure TTestWorkStealingQueue.TestPop;
  961. Var
  962. I : Integer;
  963. IP : Int64;
  964. begin
  965. For I:=1 to 20 do
  966. FQueue.LocalPush(I);
  967. For I:=1 to 20 do
  968. if not FQueue.LocalPop(IP) then
  969. Fail('Failed to pop at '+IntToStr(I))
  970. else
  971. AssertEquals('Correct value popped at '+IntToStr(I),21-I,IP);
  972. AssertEquals('Length',0,FQueue.Count);
  973. end;
  974. procedure TTestWorkStealingQueue.TestPopThreaded;
  975. Var
  976. I : INteger;
  977. L2,L1 : TInt64DynArray;
  978. begin
  979. FWaitTerminatedCount:=2;
  980. For I:=1 to 20 do
  981. FQueue.LocalPush(I);
  982. SetLength(L1,10);
  983. SetLength(L2,10);
  984. TPopThread.Create(FQueue,L1,@ThreadTerminated);
  985. TPopThread.Create(FQueue,L2,@ThreadTerminated);
  986. AssertEquals('All added',True,WaitForCondition(@WaitForTerminateCount,4000));
  987. AssertNoThreadErrors;
  988. AssertEquals('Length',0,FQueue.Count);
  989. end;
  990. procedure TTestWorkStealingQueue.TestPopThreadedErr;
  991. Var
  992. I : INteger;
  993. L2,L1 : TInt64DynArray;
  994. begin
  995. FWaitTerminatedCount:=2;
  996. For I:=1 to 20 do
  997. FQueue.LocalPush(I);
  998. SetLength(L1,20);
  999. SetLength(L2,20);
  1000. TPopThread.Create(FQueue,L1,@ThreadTerminated);
  1001. TPopThread.Create(FQueue,L2,@ThreadTerminated);
  1002. AssertEquals('All added',True,WaitForCondition(@WaitForTerminateCount,4000));
  1003. AssertThreadErrors;
  1004. AssertEquals('Length',0,FQueue.Count);
  1005. end;
  1006. procedure TTestWorkStealingQueue.TestSteal;
  1007. var
  1008. I : Int64;
  1009. begin
  1010. FWaitTerminatedCount:=1;
  1011. TSingleAddThread.Create(FQueue,100,321,@ThreadTerminated);
  1012. AssertTrue('Can steal',FQueue.TrySteal(I,400));
  1013. AssertEquals('All added',True,WaitForCondition(@WaitForTerminateCount,4000));
  1014. AssertEquals('Correct popped',321,I);
  1015. end;
  1016. procedure TTestWorkStealingQueue.TestStealFailTimeout;
  1017. var
  1018. I : Int64;
  1019. begin
  1020. FWaitTerminatedCount:=1;
  1021. TSingleAddThread.Create(FQueue,1000,321,@ThreadTerminated);
  1022. AssertFalse('Cannot steal',FQueue.TrySteal(I,400));
  1023. AssertEquals('All added',True,WaitForCondition(@WaitForTerminateCount,4000));
  1024. end;
  1025. procedure TTestWorkStealingQueue.TestRemove;
  1026. var
  1027. I : integer;
  1028. begin
  1029. For I:=1 to 20 do
  1030. FQueue.LocalPush(I);
  1031. AssertEquals('Count before',20,FQueue.Count);
  1032. AssertTrue('Remove existing',FQueue.Remove(18));
  1033. AssertEquals('Count after',19,FQueue.Count);
  1034. AssertFalse('Remove un existing',FQueue.Remove(33));
  1035. AssertEquals('Count after 2',19,FQueue.Count);
  1036. end;
  1037. procedure TTestWorkStealingQueue.TestFindAndRemove;
  1038. var
  1039. I : integer;
  1040. begin
  1041. For I:=1 to 20 do
  1042. FQueue.LocalPush(I);
  1043. AssertEquals('Count before',20,FQueue.Count);
  1044. AssertTrue('Remove existing',FQueue.LocalFindAndRemove(18));
  1045. AssertEquals('Count after',19,FQueue.Count);
  1046. AssertFalse('Remove un existing',FQueue.LocalFindAndRemove(33));
  1047. AssertEquals('Count after 2',19,FQueue.Count);
  1048. end;
  1049. { TTestWorkStealingQueue.TWorkQueueThread }
  1050. constructor TTestWorkStealingQueue.TWorkQueueThread.Create(aQueue: TMyWorkQueue; aList: TInt64DynArray; aOnDestroy: TNotifyEvent);
  1051. begin
  1052. FList:=aList;
  1053. FQueue:=aQueue;
  1054. Inherited Create(aOnDestroy);
  1055. end;
  1056. { TTestWorkStealingQueue.TAddThread }
  1057. procedure TTestWorkStealingQueue.TPushThread.Execute;
  1058. var
  1059. I : Int64;
  1060. begin
  1061. For I in FList do
  1062. begin
  1063. Sleep(Random(100));
  1064. {$IFDEF DEBUGTEST}
  1065. Writeln('Pushing');
  1066. {$ENDIF}
  1067. FQueue.LocalPush(I);
  1068. end;
  1069. {$IFDEF DEBUGTEST}
  1070. Writeln('Done');
  1071. {$ENDIF}
  1072. end;
  1073. { TTestWorkStealingQueue.TSingleAddThread }
  1074. constructor TTestWorkStealingQueue.TSingleAddThread.Create(aQueue: TMyWorkQueue; aSleep : integer; aValue: Int64; aOnDestroy: TNotifyEvent);
  1075. begin
  1076. FValue:=aValue;
  1077. FQueue:=aQueue;
  1078. FSleep:=aSleep;
  1079. Inherited Create(aOnDestroy);
  1080. end;
  1081. procedure TTestWorkStealingQueue.TSingleAddThread.Execute;
  1082. begin
  1083. Sleep(FSleep);
  1084. FQueue.LocalPush(FValue);
  1085. end;
  1086. { TTestWorkStealingQueue.TRemoveThread }
  1087. procedure TTestWorkStealingQueue.TPopThread.Execute;
  1088. var
  1089. i : Integer;
  1090. begin
  1091. For I:=0 to Length(FList)-1 do
  1092. begin
  1093. Sleep(Random(100));
  1094. if not FQueue.LocalPop(FList[I]) then
  1095. raise Exception.CreateFmt('Failed to get item %d',[I]);
  1096. end;
  1097. end;
  1098. { TCachedObject }
  1099. class function TCachedObject.newinstance: tobject;
  1100. var
  1101. Obj : Pointer;
  1102. begin
  1103. Result:=Nil;
  1104. if Assigned(_cache) then
  1105. begin
  1106. Obj:=_cache.Remove;
  1107. if Assigned(Obj) then
  1108. Result:=InitInstance(Obj);
  1109. end;
  1110. If Not Assigned(Result) then
  1111. Result:=inherited NewInstance;
  1112. end;
  1113. procedure TCachedObject.FreeInstance;
  1114. begin
  1115. CleanupInstance;
  1116. if Assigned(_Cache) then
  1117. if _Cache.Insert(Pointer(Self)) then
  1118. Exit;
  1119. Inherited;
  1120. end;
  1121. { TTestObjectCache }
  1122. procedure TTestObjectCache.ActivateCache;
  1123. begin
  1124. TCachedObject._Cache:=FCache;
  1125. end;
  1126. procedure TTestObjectCache.DeActivateCache;
  1127. begin
  1128. TCachedObject._Cache:=Nil;
  1129. end;
  1130. procedure TTestObjectCache.SetUp;
  1131. begin
  1132. inherited SetUp;
  1133. FCache:=TObjectCache.Create(TCachedObject);
  1134. end;
  1135. procedure TTestObjectCache.TearDown;
  1136. begin
  1137. TCachedObject._Cache:=Nil;
  1138. FreeAndNil(FCache);
  1139. inherited TearDown;
  1140. end;
  1141. procedure TTestObjectCache.TestHookup;
  1142. begin
  1143. AssertNotNull('Have cache',Cache);
  1144. AssertNull('Cache not active',TCachedObject._Cache);
  1145. end;
  1146. procedure TTestObjectCache.TestAdd;
  1147. Var
  1148. Obj : TCachedObject;
  1149. begin
  1150. // Create without cache.
  1151. Obj:=TCachedObject.Create;
  1152. Cache.Insert(Obj);
  1153. AssertEquals('Count',1,Cache.Count);
  1154. // The memory of the object is now managed by the cache.
  1155. end;
  1156. procedure TTestObjectCache.TestClear;
  1157. Var
  1158. Obj : TCachedObject;
  1159. I : integer;
  1160. begin
  1161. // Create without cache.
  1162. For I:=1 to 10 do
  1163. begin
  1164. Obj:=TCachedObject.Create;
  1165. Cache.Insert(Obj);
  1166. end;
  1167. // The memory of the objects is now managed by the cache.
  1168. AssertEquals('Count',10,Cache.Count);
  1169. Cache.Clear;
  1170. AssertEquals('Count',0,Cache.Count);
  1171. end;
  1172. procedure TTestObjectCache.TestRemove;
  1173. Var
  1174. Obj : Array[1..10] of TCachedObject;
  1175. I : integer;
  1176. P : Pointer;
  1177. begin
  1178. // Create without cache.
  1179. For I:=1 to 10 do
  1180. begin
  1181. Obj[i]:=TCachedObject.Create;
  1182. AssertTrue('Insert '+IntToStr(I)+'OK',Cache.Insert(Obj[i]));
  1183. end;
  1184. // The memory of the objects is now managed by the cache.
  1185. AssertEquals('Count',10,Cache.Count);
  1186. For I:=1 to 10 do
  1187. begin
  1188. P:=Cache.Remove;
  1189. AssertNotNull('Got pointer',P);
  1190. // Free the memory.
  1191. FreeMem(P);
  1192. end;
  1193. AssertNull('No 11th pointer',Cache.Remove);
  1194. end;
  1195. procedure TTestObjectCache.TestCreate;
  1196. Var
  1197. Obj : Array[1..10] of TCachedObject;
  1198. I : Integer;
  1199. begin
  1200. ActivateCache;
  1201. For I:=1 to 10 do
  1202. Obj[i]:=TCachedObject.Create;
  1203. // nothing in cache yet.
  1204. AssertEquals('Count',0,Cache.Count);
  1205. For I:=1 to 10 do
  1206. FreeAndNil(Obj[i]);
  1207. // All objects should be in cache.
  1208. AssertEquals('Count',10,Cache.Count);
  1209. For I:=1 to 10 do
  1210. Obj[i]:=TCachedObject.Create;
  1211. // Pointers from cache should have been reused.
  1212. AssertEquals('Count',0,Cache.Count);
  1213. DeActivateCache;
  1214. For I:=1 to 10 do
  1215. FreeAndNil(Obj[i]);
  1216. // Cache was disabled, to object should have been freed...
  1217. AssertEquals('Count',0,Cache.Count);
  1218. end;
  1219. { TTestObjectCaches }
  1220. procedure TTestObjectCaches.Setup;
  1221. begin
  1222. inherited Setup;
  1223. FCaches:=TObjectCaches.Create([doOwnsValues]);
  1224. end;
  1225. procedure TTestObjectCaches.TearDown;
  1226. begin
  1227. FreeAndNil(FCaches);
  1228. inherited TearDown;
  1229. end;
  1230. procedure TTestObjectCaches.TestHookup;
  1231. begin
  1232. AssertNotNull('Have caches',Caches);
  1233. end;
  1234. procedure TTestObjectCaches.TestAdd;
  1235. begin
  1236. Caches.AddObjectCache(TCachedObject);
  1237. AssertEquals('Count',1,Caches.Count);
  1238. end;
  1239. procedure TTestObjectCaches.TestGetValue;
  1240. var
  1241. C : TObjectCache;
  1242. begin
  1243. TestAdd;
  1244. AssertFalse('Get cache (nok)',Caches.TryGetValue(TComponent,C));
  1245. AssertTrue('Get cache (ok)',Caches.TryGetValue(TCachedObject,C));
  1246. AssertEquals('Count',1,Caches.Count);
  1247. end;
  1248. { TTestThreading }
  1249. procedure TTestThreading.TestHookUp;
  1250. begin
  1251. AssertNotNull('Have Default',TThreadPool.Default);
  1252. AssertNotNull('Have current',TThreadPool.Current);
  1253. AssertNotNull('Have instance',FThreadPool);
  1254. end;
  1255. procedure TTestThreading.TestCurrentOutsideTask;
  1256. begin
  1257. AssertSame('Current is default outside task',TThreadPool.Default,TThreadPool.Current);
  1258. end;
  1259. procedure TTestThreading.TestSetMaxWorkerThreads;
  1260. var
  1261. C : Integer;
  1262. begin
  1263. C:=FThreadPool.MaxWorkerThreads;
  1264. try
  1265. AssertFalse('No zero',FThreadPool.SetMaxWorkerThreads(0));
  1266. AssertFalse('Bigger than min',FThreadPool.SetMaxWorkerThreads(FThreadPool.MinWorkerThreads));
  1267. AssertTrue('Big value',FThreadPool.SetMaxWorkerThreads(256));
  1268. finally
  1269. FThreadPool.SetMaxWorkerThreads(C);
  1270. end;
  1271. end;
  1272. procedure TTestThreading.TestSetMinWorkerThreads;
  1273. var
  1274. C : Integer;
  1275. begin
  1276. C:=FThreadPool.MinWorkerThreads;
  1277. try
  1278. AssertFalse('No negative',FThreadPool.SetMinWorkerThreads(-1));
  1279. AssertFalse('Smaller than max',FThreadPool.SetMinWorkerThreads(FThreadPool.MaxWorkerThreads+1));
  1280. AssertTrue('zero',FThreadPool.SetMinWorkerThreads(0));
  1281. finally
  1282. FThreadPool.SetMinWorkerThreads(C);
  1283. end;
  1284. end;
  1285. procedure TTestThreading.DoSimpleExecute(Sender : TObject);
  1286. begin
  1287. AssertSame('Sender',Self,Sender);
  1288. ThreadTerminated(TThread.CurrentThread); // Will reduce count
  1289. end;
  1290. procedure TTestThreading.WaitForWorkDoneCount(out Done: Boolean);
  1291. begin
  1292. Done:=(WorkCount>0) and (WorkDone>=WorkCount);
  1293. {$IFDEF DEBUGTEST}
  1294. Writeln('Done:=(',WorkCount,'>0) and (',WorkDone,'>=',WorkCount,') -> ',Done);
  1295. {$ENDIF}
  1296. end;
  1297. procedure TTestThreading.DoThreadTerminate(arg: TThread);
  1298. begin
  1299. AtomicIncrement(FThreadsTerminated);
  1300. end;
  1301. procedure TTestThreading.DoThreadStart(arg: TThread);
  1302. begin
  1303. AtomicIncrement(FThreadsStarted);
  1304. end;
  1305. procedure TTestThreading.DoBurnCyclesExecute(Sender : TObject);
  1306. var
  1307. Cycles : Integer;
  1308. I,J,K,BurnCount : Integer;
  1309. T : TDateTime;
  1310. begin
  1311. {$IFDEF DEBUGTEST}
  1312. Writeln('Thread ',TThread.CurrentThread.ThreadID,': Starting');
  1313. {$ENDIF}
  1314. AssertSame('Sender',Self,Sender);
  1315. T:=Now;
  1316. Cycles:=10+Random(2);
  1317. For I:=1 to Cycles do
  1318. begin
  1319. BurnCount:=100000*(1+Random(5));
  1320. For J:=1 to BurnCount do
  1321. if (J and 1)=1 then
  1322. K:=K+J
  1323. else
  1324. K:=K-J;
  1325. Sleep(10+Random(10));
  1326. end;
  1327. {$IFDEF DEBUGTEST}
  1328. Writeln('Thread ',TThread.CurrentThread.ThreadID,': worked milliseconds ',MillisecondsBetween(Now,T));
  1329. {$ENDIF}
  1330. // ThreadTerminated(TThread.CurrentThread); // Will reduce count
  1331. AtomicIncrement(FWorkDone);
  1332. {$IFDEF DEBUGTEST}
  1333. Writeln('Thread ',TThread.CurrentThread.ThreadID,': Work Done ',FTerminatedCount) ;
  1334. {$ENDIF}
  1335. end;
  1336. procedure TTestThreading.TestExecuteWork;
  1337. begin
  1338. FWaitTerminatedCount:=1;
  1339. FThreadPool.QueueWorkItem(Self,@DoSimpleExecute);
  1340. AssertTrue('Task executed',WaitForCondition(@WaitForTerminateCount,500));
  1341. end;
  1342. procedure TTestThreading.TestExecuteLotsOfWork;
  1343. var
  1344. i, Count : Integer;
  1345. {$IFDEF DEBUGTEST}
  1346. T : TDateTime;
  1347. {$ENDIF}
  1348. begin
  1349. Count:=TThread.ProcessorCount*2;
  1350. WorkCount:=Count;
  1351. {$IFDEF DEBUGTEST}
  1352. T:=Now;
  1353. {$ENDIF}
  1354. For I:=1 to Count do
  1355. begin
  1356. {$IFDEF DEBUGTEST}
  1357. Writeln('Main loop queueing work item ',I,'/',count);
  1358. {$ENDIF}
  1359. FThreadPool.QueueWorkItem(Self,@DoBurnCyclesExecute);
  1360. {$IFDEF DEBUGTEST}
  1361. Writeln('Main loop sleep ',I,'/',count);
  1362. {$ENDIF}
  1363. Sleep(4);
  1364. {$IFDEF DEBUGTEST}
  1365. Writeln('Main loop wake ',I,'/',count);
  1366. {$ENDIF}
  1367. end;
  1368. AssertTrue('Tasks executed',WaitForCondition(@WaitForWorkDoneCount,10000));
  1369. {$IFDEF DEBUGTEST}
  1370. Writeln('Milliseconds ',MillisecondsBetween(Now,T));
  1371. {$ENDIF}
  1372. FreeAndNil(FThreadPool);
  1373. AssertEquals('Threads all stopped',FThreadsStarted,FThreadsTerminated);
  1374. end;
  1375. procedure TTestThreading.SetUp;
  1376. begin
  1377. Inherited;
  1378. FThreadPool:=TThreadPool.Create;
  1379. FThreadPool.OnThreadStart:=@DoThreadStart;
  1380. FThreadPool.OnThreadTerminate:=@DoThreadTerminate;
  1381. FThreadsTerminated:=0;
  1382. FThreadsStarted:=0;
  1383. end;
  1384. procedure TTestThreading.TearDown;
  1385. begin
  1386. FreeAndNil(FThreadPool);
  1387. Inherited;
  1388. end;
  1389. { TTestTask }
  1390. procedure TTestTask.OnTask(Sender : TObject);
  1391. begin
  1392. AssertSame('Sender',Self,Sender);
  1393. AssertSame('Current task',FTask,TTask.CurrentTask);
  1394. // Writeln('FTask.Status = ',FTask.Status,', current : ',TTask.CurrentTask.Status); //TTaskStatus.Running
  1395. AssertTrue('Task status',TTask.CurrentTask.Status=TTaskStatus.Running);
  1396. if FRaise then
  1397. Raise ESomeThing.Create('MrDo');
  1398. FWorkExecuted:=True;
  1399. end;
  1400. procedure TTestTask.SetUp;
  1401. begin
  1402. inherited SetUp;
  1403. CreateTask;
  1404. end;
  1405. procedure TTestTask.CreateTask;
  1406. begin
  1407. FTask:=TTask.Create(Self,@OnTask);
  1408. FWorkExecuted:=False;
  1409. FRaise:=False;
  1410. end;
  1411. procedure TTestTask.TearDown;
  1412. begin
  1413. FTask:=Nil;
  1414. inherited TearDown;
  1415. end;
  1416. procedure TTestTask.TestHookup;
  1417. begin
  1418. AssertNotNull('Have task',Task);
  1419. AssertFalse('Work not executed',FWorkExecuted);
  1420. end;
  1421. procedure TTestTask.TestId;
  1422. var
  1423. aID : Integer;
  1424. begin
  1425. aID:=Task.Id;
  1426. AssertTrue('Have ID',aID>0);
  1427. CreateTask;
  1428. AssertTrue('Have new ID',Task.ID<>aID);
  1429. end;
  1430. procedure TTestTask.TestStatus;
  1431. begin
  1432. AssertTrue('Status created',Task.Status=TTaskStatus.Created);
  1433. end;
  1434. procedure TTestTask.TestShouldExecute;
  1435. begin
  1436. AssertFalse('Should execute',Task.ShouldExecute);
  1437. end;
  1438. procedure TTestTask.TestExecuteWork;
  1439. begin
  1440. Task.ExecuteWork;
  1441. AssertTrue('Work executed',FWorkExecuted);
  1442. AssertTrue('Status',Task.Status=TTaskStatus.Completed);
  1443. end;
  1444. procedure TTestTask.TestExecuteWorkException;
  1445. begin
  1446. FRaise:=True;
  1447. Task.ExecuteWork;
  1448. AssertFalse('Work executed',FWorkExecuted);
  1449. AssertTrue('Status',Task.Status=TTaskStatus.Exception);
  1450. end;
  1451. procedure TTestTask.TestWaitCardinal;
  1452. begin
  1453. TStartTaskThread.Create(Task,200);
  1454. AssertTrue('Wait OK',Task.Wait(400));
  1455. AssertTrue('Work executed',FWorkExecuted);
  1456. end;
  1457. procedure TTestTask.TestWaitTimeSpan;
  1458. var
  1459. T: TTimespan;
  1460. begin
  1461. TStartTaskThread.Create(Task,200);
  1462. T:=TTimeSpan.Create(0,0,0,0,400);
  1463. AssertTrue('Wait OK',Task.Wait(T));
  1464. AssertTrue('Work executed',FWorkExecuted);
  1465. end;
  1466. procedure TTestTask.TestCancel;
  1467. begin
  1468. Task.Start;
  1469. AssertTrue('Status',Task.Status>=TTaskStatus.WaitingToRun);
  1470. Task.Cancel;
  1471. AssertFalse('Work executed',FWorkExecuted);
  1472. end;
  1473. procedure TTestTask.TestCheckCanceled;
  1474. begin
  1475. Task.Start;
  1476. AssertTrue('Status',Task.Status>=TTaskStatus.WaitingToRun);
  1477. Task.Cancel;
  1478. AssertException('Cancel raises',EOperationCancelled,@CheckTaskCanceled);
  1479. end;
  1480. procedure TTestTask.TestStart;
  1481. begin
  1482. Task.Start;
  1483. AssertTrue('Status',Task.Status>=TTaskStatus.WaitingToRun);
  1484. Task.Wait;
  1485. AssertTrue('Work executed',FWorkExecuted);
  1486. end;
  1487. procedure TTestTask.TestStartTwice;
  1488. begin
  1489. Task.Start;
  1490. AssertTrue('Status',Task.Status>=TTaskStatus.WaitingToRun);
  1491. Task.Wait;
  1492. AssertTrue('Work executed',FWorkExecuted);
  1493. AssertException('Cannot start twice',EInvalidOperation,@StartTask);
  1494. end;
  1495. procedure TTestTask.WaitForTask;
  1496. begin
  1497. Task.Wait;
  1498. end;
  1499. procedure TTestTask.StartTask;
  1500. begin
  1501. Task.Start;
  1502. end;
  1503. procedure TTestTask.CheckTaskCanceled;
  1504. begin
  1505. Task.CheckCanceled;
  1506. end;
  1507. procedure TTestTask.TestStartException;
  1508. begin
  1509. FRaise:=true;
  1510. Task.Start;
  1511. AssertTrue('Status',Task.Status=TTaskStatus.WaitingToRun);
  1512. AssertException('Exception',EAggregateException,@WaitForTask);
  1513. AssertFalse('Work executed',FWorkExecuted);
  1514. end;
  1515. function CalcInteger : Integer;
  1516. begin
  1517. Sleep(40);
  1518. Result:=42;
  1519. end;
  1520. procedure TTestTask.TestFuture;
  1521. begin
  1522. AssertEquals('Calc future',42,(TTask.Specialize Future<Integer>(@CalcInteger)).Value)
  1523. end;
  1524. function TTestTask.CalcIntegerEvent(Sender : TObject) : Integer;
  1525. begin
  1526. // Writeln('Here');
  1527. Sleep(40);
  1528. AssertSame('Sender',self,Sender);
  1529. Result:=43;
  1530. // Writeln('Here 2');
  1531. end;
  1532. procedure TTestTask.TestFutureEvent;
  1533. begin
  1534. AssertEquals('Calc future',43,(TTask.Specialize Future<Integer>(Self,@CalcIntegerEvent)).Value)
  1535. end;
  1536. { TTestTask.TTaskThread }
  1537. constructor TTestTask.TTaskThread.Create(aTask: ITask; aSleep: Integer);
  1538. begin
  1539. FTask:=aTask;
  1540. FSleep:=aSleep;
  1541. FreeOnTerminate:=True;
  1542. Inherited Create(False);
  1543. end;
  1544. procedure TTestTask.TTaskThread.Execute;
  1545. var
  1546. OK : Boolean;
  1547. begin
  1548. Sleep(FSleep);
  1549. try
  1550. OK:=False;
  1551. DoTask(FTask);
  1552. OK:=True;
  1553. finally
  1554. FTask:=Nil;
  1555. // Writeln('Task done. No errors: ',OK);
  1556. end;
  1557. end;
  1558. { TTestTask.TStartTaskThread }
  1559. procedure TTestTask.TStartTaskThread.DoTask(aTask: ITask);
  1560. begin
  1561. aTask.Start;
  1562. end;
  1563. { TTestParallel }
  1564. procedure TTestParallel.SetUp;
  1565. begin
  1566. inherited SetUp;
  1567. FResults:=Default(TResultArray);
  1568. _Results:=Default(TResultArray);
  1569. end;
  1570. procedure TTestParallel.TearDown;
  1571. begin
  1572. inherited TearDown;
  1573. end;
  1574. procedure TTestParallel.CheckLocal;
  1575. var
  1576. I : integer;
  1577. begin
  1578. For I:=1 to 255 do
  1579. AssertEquals('Element '+IntToStr(i),I,FResults[i]);
  1580. end;
  1581. procedure TTestParallel.TestHookup;
  1582. var
  1583. I : integer;
  1584. begin
  1585. For I:=1 to 255 do
  1586. AssertEquals('Element '+IntToStr(i),0,FResults[i]);
  1587. For I:=1 to 255 do
  1588. AssertEquals('GLobal Element '+IntToStr(i),0,_Results[i]);
  1589. end;
  1590. procedure TTestParallel.DoEvent(aSender: TObject; aIndex: Integer);
  1591. begin
  1592. // Writeln(TThread.CurrentThread.ThreadID,' EventIdx ',aIndex);
  1593. Sleep(50+(10*(1+Random(5))));
  1594. FResults[aIndex]:=aIndex;
  1595. end;
  1596. procedure TTestParallel.DoEvent64(aSender: TObject; aIndex: Int64);
  1597. begin
  1598. Sleep(50+(10*(1+Random(5))));
  1599. FResults[aIndex]:=aIndex;
  1600. end;
  1601. procedure TTestParallel.TestForEvent;
  1602. var
  1603. L : TParallel.TLoopResult;
  1604. begin
  1605. L:=TParallel.&For(Self,1,1,255,@DoEvent);
  1606. AssertTrue('Correct result',L.Completed);
  1607. CheckLocal;
  1608. end;
  1609. {$IFDEF CPU64}
  1610. procedure TTestParallel.TestForEvent64;
  1611. var
  1612. L : TParallel.TLoopResult;
  1613. begin
  1614. L:=TParallel.&For(Self,1,1,255,@DoEvent64);
  1615. AssertTrue('Correct result',L.Completed);
  1616. CheckLocal;
  1617. end;
  1618. {$ENDIF}
  1619. initialization
  1620. RegisterTests([
  1621. TTestTExceptionList,
  1622. TTestAggregateException,
  1623. TTestSparseArray,
  1624. TTestWorkStealingQueue,
  1625. TTestObjectCache,
  1626. TTestObjectCaches,
  1627. TTestThreading,
  1628. TTestTask,
  1629. TTestParallel
  1630. ]);
  1631. end.