Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

121 linhas
2.4 KiB

  1. unit uutlSyncObjs;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, syncobjs;
  6. type
  7. TAutoResetEvent = class(TEvent)
  8. public
  9. constructor Create(aInitial: boolean = false);
  10. end;
  11. // aliased to stay in LCL naming scheme for TSimpleEvent
  12. TutlAutoResetEvent = TAutoResetEvent;
  13. TutlSpinLock = class
  14. private
  15. fLock: DWord;
  16. fLockReused: integer;
  17. public
  18. constructor Create;
  19. destructor Destroy; override;
  20. procedure Enter;
  21. procedure Leave;
  22. end;
  23. generic IutlLock<T> = interface(IUnknown)
  24. function LockedObject: T;
  25. end;
  26. generic TutlLock<T> = class(TInterfacedObject, specialize IutlLock<T>)
  27. private
  28. fLock: TCriticalSection;
  29. fObject: T;
  30. public
  31. function LockedObject: T;
  32. constructor Create(const aLock: TCriticalSection; const aObject: T);
  33. destructor Destroy; override;
  34. end;
  35. implementation
  36. { TAutoResetEvent }
  37. constructor TAutoResetEvent.Create(aInitial: boolean);
  38. begin
  39. inherited Create(Nil, false, aInitial, '');
  40. end;
  41. { TutlSpinLock }
  42. constructor TutlSpinLock.Create;
  43. begin
  44. inherited Create;
  45. fLock:= 0;
  46. fLockReused:= 0;
  47. end;
  48. destructor TutlSpinLock.Destroy;
  49. begin
  50. Enter;
  51. inherited Destroy;
  52. end;
  53. procedure TutlSpinLock.Enter;
  54. var
  55. ti: dword;
  56. begin
  57. ti:= ThreadID;
  58. if ti = InterlockedCompareExchange(fLock, ti, ti) then begin
  59. {
  60. The lock is already held by this thread. This means it cannot be modified by a concurrent
  61. operation (assuming Enter/Leave bracket correctly), and we can act non-atomar on other variables.
  62. }
  63. inc(fLockReused);
  64. end else begin
  65. while InterlockedCompareExchange(fLock, ti, 0) <> 0 do ;
  66. end;
  67. end;
  68. procedure TutlSpinLock.Leave;
  69. var
  70. ti: DWord;
  71. begin
  72. ti:= ThreadID;
  73. // Unlock only if we hold the lock
  74. if ti = InterlockedCompareExchange(fLock, ti, ti) then begin
  75. // our lock, but we haven't yet done anything (note the above is essentially a threadsafe CMP if successful)
  76. if fLockReused = 0 then
  77. InterLockedExchange(fLock, 0) // normal lock
  78. else
  79. dec(fLockReused); // nested locks
  80. end;
  81. end;
  82. function TutlLock.LockedObject: T;
  83. begin
  84. result := fObject;
  85. end;
  86. constructor TutlLock.Create(const aLock: TCriticalSection; const aObject: T);
  87. begin
  88. inherited Create;
  89. if not Assigned(aLock) then
  90. raise EArgumentNilException.Create('aLock');
  91. fLock := aLock;
  92. fLock.Enter;
  93. fObject := aObject;
  94. end;
  95. destructor TutlLock.Destroy;
  96. begin
  97. fLock.Leave;
  98. inherited Destroy;
  99. end;
  100. end.