Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

281 строка
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. result := wrError;
  145. timeout := GetTickCount64 + aTimeout;
  146. for i := 0 to Count-1 do begin
  147. if (aTimeout <> INFINITE) then begin
  148. tick := GetTickCount64;
  149. if (tick >= timeout) then begin
  150. result := wrTimeout;
  151. exit;
  152. end else
  153. result := Items[i].WaitFor(timeout - tick);
  154. end else
  155. result := Items[i].WaitFor(INFINITE);
  156. if result <> wrSignaled then
  157. exit;
  158. end;
  159. end;
  160. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  161. constructor TutlEventList.Create;
  162. begin
  163. inherited Create(true);
  164. end;
  165. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  166. //TAutoResetEvent///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  167. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  168. constructor TAutoResetEvent.Create(const aInitial: boolean);
  169. begin
  170. inherited Create(Nil, false, aInitial, '');
  171. end;
  172. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  173. //TutlSpinLock//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  174. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  175. procedure TutlSpinLock.Enter;
  176. var
  177. ti: DWord;
  178. begin
  179. ti := ThreadID;
  180. if (ti = InterlockedCompareExchange(fLock, ti, ti)) then begin
  181. {
  182. The lock is already held by this thread. This means it cannot be modified by a concurrent
  183. operation (assuming Enter/Leave bracket correctly), and we can act non-atomar on other variables.
  184. }
  185. inc(fLockReused);
  186. end else begin
  187. while InterlockedCompareExchange(fLock, ti, 0) <> 0 do ;
  188. end;
  189. end;
  190. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  191. procedure TutlSpinLock.Leave;
  192. var
  193. ti: DWord;
  194. begin
  195. ti := ThreadID;
  196. // Unlock only if we hold the lock
  197. if (ti = InterlockedCompareExchange(fLock, ti, ti)) then begin
  198. // our lock, but we haven't yet done anything (note the above is essentially a threadsafe CMP if successful)
  199. if fLockReused = 0 then
  200. InterLockedExchange(fLock, 0) // normal lock
  201. else
  202. dec(fLockReused); // nested locks
  203. end;
  204. end;
  205. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  206. constructor TutlSpinLock.Create;
  207. begin
  208. inherited Create;
  209. fLock := 0;
  210. fLockReused := 0;
  211. end;
  212. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  213. destructor TutlSpinLock.Destroy;
  214. begin
  215. Enter;
  216. inherited Destroy;
  217. end;
  218. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  219. //TutlLock//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  220. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  221. function TutlLock.LockedObject: T;
  222. begin
  223. result := fObject;
  224. end;
  225. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  226. constructor TutlLock.Create(const aLock: TCriticalSection; const aObject: T);
  227. begin
  228. inherited Create;
  229. if not Assigned(aLock) then
  230. raise EArgumentNilException.Create('aLock');
  231. fObject := aObject;
  232. fLock := aLock;
  233. fLock.Enter;
  234. end;
  235. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  236. destructor TutlLock.Destroy;
  237. begin
  238. fLock.Leave;
  239. inherited Destroy;
  240. end;
  241. end.