25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 

280 satır
11 KiB

  1. unit uutlSyncObjs;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, syncobjs,
  6. uutlGenerics;
  7. type
  8. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  9. TutlCheckSynchronizeEvent = class(TObject)
  10. private
  11. fEvent: TEvent;
  12. function WaitMainThread(const aTimeout: Cardinal): TWaitResult;
  13. public const
  14. MAIN_WAIT_GRANULARITY = 10;
  15. public
  16. procedure SetEvent;
  17. procedure ResetEvent;
  18. function WaitFor(const aTimeout: Cardinal): TWaitResult;
  19. constructor Create(
  20. const aEventAttributes: PSecurityAttributes;
  21. const aManualReset: Boolean;
  22. const aInitialState: Boolean;
  23. const aName: string);
  24. destructor Destroy; override;
  25. end;
  26. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  27. TutlEventList = class(specialize TutlSimpleList<TutlCheckSynchronizeEvent>)
  28. public
  29. function AddEvent(
  30. const aEventAttributes: PSecurityAttributes;
  31. const aManualReset: Boolean;
  32. const aInitialState: Boolean;
  33. const aName: String): TutlCheckSynchronizeEvent;
  34. function AddDefaultEvent: TutlCheckSynchronizeEvent;
  35. function WaitAll(const aTimeout: Cardinal): TWaitResult;
  36. constructor Create;
  37. end;
  38. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  39. TAutoResetEvent = class(TEvent)
  40. public
  41. constructor Create(const aInitial: boolean = false);
  42. end;
  43. // aliased to stay in LCL naming scheme for TSimpleEvent
  44. TutlAutoResetEvent = TAutoResetEvent;
  45. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  46. TutlSpinLock = class
  47. private
  48. fLock: DWord;
  49. fLockReused: integer;
  50. public
  51. procedure Enter;
  52. procedure Leave;
  53. constructor Create;
  54. destructor Destroy; override;
  55. end;
  56. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  57. generic IutlLock<T> = interface(IUnknown)
  58. function LockedObject: T;
  59. end;
  60. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  61. generic TutlLock<T> = class(
  62. TInterfacedObject,
  63. specialize IutlLock<T>)
  64. private
  65. fLock: TCriticalSection;
  66. fObject: T;
  67. public
  68. function LockedObject: T; inline;
  69. constructor Create(const aLock: TCriticalSection; const aObject: T);
  70. destructor Destroy; override;
  71. end;
  72. implementation
  73. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  74. //TutlCheckSynchronizeEvent/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  75. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  76. function TutlCheckSynchronizeEvent.WaitMainThread(const aTimeout: Cardinal): TWaitResult;
  77. var
  78. timeout: qword;
  79. begin
  80. timeout:= GetTickCount64 + aTimeout;
  81. repeat
  82. result := fEvent.WaitFor(TutlCheckSynchronizeEvent.MAIN_WAIT_GRANULARITY);
  83. CheckSynchronize();
  84. until (result <> wrTimeout) or ((GetTickCount64 > timeout) and (aTimeout <> INFINITE));
  85. end;
  86. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  87. procedure TutlCheckSynchronizeEvent.SetEvent;
  88. begin
  89. fEvent.SetEvent;
  90. end;
  91. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  92. procedure TutlCheckSynchronizeEvent.ResetEvent;
  93. begin
  94. fEvent.ResetEvent;
  95. end;
  96. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  97. function TutlCheckSynchronizeEvent.WaitFor(const aTimeout: Cardinal): TWaitResult;
  98. begin
  99. if (GetCurrentThreadId = MainThreadID) then
  100. result := WaitMainThread(aTimeout)
  101. else
  102. result := fEvent.WaitFor(aTimeout);
  103. end;
  104. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  105. constructor TutlCheckSynchronizeEvent.Create(
  106. const aEventAttributes: PSecurityAttributes;
  107. const aManualReset: Boolean;
  108. const aInitialState: Boolean;
  109. const aName: string);
  110. begin
  111. inherited Create;
  112. fEvent := TEvent.Create(aEventAttributes, aManualReset, aInitialState, aName);
  113. end;
  114. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  115. destructor TutlCheckSynchronizeEvent.Destroy;
  116. begin
  117. FreeAndNil(fEvent);
  118. inherited Destroy;
  119. end;
  120. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  121. //TutlEventList/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  122. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  123. function TutlEventList.AddEvent(
  124. const aEventAttributes: PSecurityAttributes;
  125. const aManualReset: Boolean;
  126. const aInitialState: Boolean;
  127. const aName: String): TutlCheckSynchronizeEvent;
  128. begin
  129. result := TutlCheckSynchronizeEvent.Create(aEventAttributes, aManualReset, aInitialState, aName);
  130. Add(result);
  131. end;
  132. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  133. function TutlEventList.AddDefaultEvent: TutlCheckSynchronizeEvent;
  134. begin
  135. result := AddEvent(nil, true, false, '');
  136. result.ResetEvent;
  137. end;
  138. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  139. function TutlEventList.WaitAll(const aTimeout: Cardinal): TWaitResult;
  140. var
  141. i: integer;
  142. timeout, tick: qword;
  143. begin
  144. timeout := GetTickCount64 + aTimeout;
  145. for i := 0 to Count-1 do begin
  146. if (aTimeout <> INFINITE) then begin
  147. tick := GetTickCount64;
  148. if (tick >= timeout) then begin
  149. result := wrTimeout;
  150. exit;
  151. end else
  152. result := Items[i].WaitFor(timeout - tick);
  153. end else
  154. result := Items[i].WaitFor(INFINITE);
  155. if result <> wrSignaled then
  156. exit;
  157. end;
  158. end;
  159. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  160. constructor TutlEventList.Create;
  161. begin
  162. inherited Create(true);
  163. end;
  164. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  165. //TAutoResetEvent///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  166. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  167. constructor TAutoResetEvent.Create(const aInitial: boolean);
  168. begin
  169. inherited Create(Nil, false, aInitial, '');
  170. end;
  171. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  172. //TutlSpinLock//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  173. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  174. procedure TutlSpinLock.Enter;
  175. var
  176. ti: DWord;
  177. begin
  178. ti := ThreadID;
  179. if (ti = InterlockedCompareExchange(fLock, ti, ti)) then begin
  180. {
  181. The lock is already held by this thread. This means it cannot be modified by a concurrent
  182. operation (assuming Enter/Leave bracket correctly), and we can act non-atomar on other variables.
  183. }
  184. inc(fLockReused);
  185. end else begin
  186. while InterlockedCompareExchange(fLock, ti, 0) <> 0 do ;
  187. end;
  188. end;
  189. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  190. procedure TutlSpinLock.Leave;
  191. var
  192. ti: DWord;
  193. begin
  194. ti := ThreadID;
  195. // Unlock only if we hold the lock
  196. if (ti = InterlockedCompareExchange(fLock, ti, ti)) then begin
  197. // our lock, but we haven't yet done anything (note the above is essentially a threadsafe CMP if successful)
  198. if fLockReused = 0 then
  199. InterLockedExchange(fLock, 0) // normal lock
  200. else
  201. dec(fLockReused); // nested locks
  202. end;
  203. end;
  204. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  205. constructor TutlSpinLock.Create;
  206. begin
  207. inherited Create;
  208. fLock := 0;
  209. fLockReused := 0;
  210. end;
  211. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  212. destructor TutlSpinLock.Destroy;
  213. begin
  214. Enter;
  215. inherited Destroy;
  216. end;
  217. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  218. //TutlLock//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  219. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  220. function TutlLock.LockedObject: T;
  221. begin
  222. result := fObject;
  223. end;
  224. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  225. constructor TutlLock.Create(const aLock: TCriticalSection; const aObject: T);
  226. begin
  227. inherited Create;
  228. if not Assigned(aLock) then
  229. raise EArgumentNilException.Create('aLock');
  230. fObject := aObject;
  231. fLock := aLock;
  232. fLock.Enter;
  233. end;
  234. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  235. destructor TutlLock.Destroy;
  236. begin
  237. fLock.Leave;
  238. inherited Destroy;
  239. end;
  240. end.