unit uutlSyncObjs; {$mode objfpc}{$H+} interface uses Classes, SysUtils, syncobjs; type TAutoResetEvent = class(TEvent) public constructor Create(aInitial: boolean = false); end; // aliased to stay in LCL naming scheme for TSimpleEvent TutlAutoResetEvent = TAutoResetEvent; TutlSpinLock = class private fLock: DWord; fLockReused: integer; public constructor Create; destructor Destroy; override; procedure Enter; procedure Leave; end; generic IutlLock = interface(IUnknown) function LockedObject: T; end; generic TutlLock = class(TInterfacedObject, specialize IutlLock) private fLock: TCriticalSection; fObject: T; public function LockedObject: T; constructor Create(const aLock: TCriticalSection; const aObject: T); destructor Destroy; override; end; implementation { TAutoResetEvent } constructor TAutoResetEvent.Create(aInitial: boolean); begin inherited Create(Nil, false, aInitial, ''); end; { TutlSpinLock } constructor TutlSpinLock.Create; begin inherited Create; fLock:= 0; fLockReused:= 0; end; destructor TutlSpinLock.Destroy; begin Enter; inherited Destroy; end; procedure TutlSpinLock.Enter; var ti: dword; begin ti:= ThreadID; if ti = InterlockedCompareExchange(fLock, ti, ti) then begin { The lock is already held by this thread. This means it cannot be modified by a concurrent operation (assuming Enter/Leave bracket correctly), and we can act non-atomar on other variables. } inc(fLockReused); end else begin while InterlockedCompareExchange(fLock, ti, 0) <> 0 do ; end; end; procedure TutlSpinLock.Leave; var ti: DWord; begin ti:= ThreadID; // Unlock only if we hold the lock if ti = InterlockedCompareExchange(fLock, ti, ti) then begin // our lock, but we haven't yet done anything (note the above is essentially a threadsafe CMP if successful) if fLockReused = 0 then InterLockedExchange(fLock, 0) // normal lock else dec(fLockReused); // nested locks end; end; function TutlLock.LockedObject: T; begin result := fObject; end; constructor TutlLock.Create(const aLock: TCriticalSection; const aObject: T); begin inherited Create; if not Assigned(aLock) then raise EArgumentNilException.Create('aLock'); fLock := aLock; fLock.Enter; fObject := aObject; end; destructor TutlLock.Destroy; begin fLock.Leave; inherited Destroy; end; end.