Rollo62 536 Posted April 14, 2021 (edited) Hi there, I'm playing around with the new TLightweightMREW, and it seems to be a custom record now. There were already some important improvements from @Primož Gabrijelčič available. In comparison to TMultiReadExclusiveWriteSynchronizer, which is a class, I ask myself if this new TLightweightMREW is intended to be used as a field over a classes lifetime. Like type TMyClass = class private FLock : TLightweightMREW; ... ... procedure DoSomeLocking; procedure DoSomeMoreLocking; procedure DoSomeLockingStart; procedure DoSomeLockingStop; ... constructor Create; destructor Destroy; override; ... end; implementation ... constructor TMyClass.Create; begin inherited; //FLock as custom record needs no special initialization ! end; procedure TMyClass.DoSomeLocking; begin FLock.BeginRead; ... FLock.EndRead; end; procedure TMyClass.DoSomeMoreLocking; begin FLock.BeginWrite; ... FLock.EndWrite; end; procedure TMyClass.DoSomeLockingStart; begin FLock.BeginWrite; ... end; procedure TMyClass.DoSomeLockingStop; begin FLock.EndWrite; end; constructor TMyClass.Destroy; begin inherited; // !! There is no way to find our if a locking is currently is running // FLock maybe destroyed when class is destroyed, the all locking released ? end; Is this kind of "class global" field, inside a class, intended to be used like that ? If so, how to manage possible hanging "locks", when the whole class is destroyed before locks were released ? Maybe its somehow guaranteed by design that FLock is releasing all locks, when the class is destroyed, but I would doubt that. So that means, I would have to put my own "lock accounting" around this TLightweightMREW field, is that correct ? Maybe this kind of use-case is not the right for the TLightweightMREW, and it better should be used only "locally" within a method ? Edited April 14, 2021 by Rollo62 Share this post Link to post
Stefan Glienke 2002 Posted April 14, 2021 There is no magic to it - it behaves exactly like SRW Locks and very similar on other platforms. And similar to TMREWSync it won't magically untangle any deadlocks or pending locks you had at the point of its destruction. The benefit of SRW locks is that they are very small - sizeof(pointer) - and can be embedded within the memory of the object which improves its performance - no memory indirection, cache locality. Share this post Link to post
Dalija Prasnikar 1396 Posted April 14, 2021 Locks of any kind used as field in a class are meant to protect integrity of the data inside object instance, not to protect that instance from being destroyed. If you need to protect particular TMyClass instance itself, you will need to use some outer locking mechanism. Share this post Link to post
Rollo62 536 Posted April 14, 2021 (edited) 3 hours ago, Dalija Prasnikar said: f you need to protect particular TMyClass instance itself, you will need to use some outer locking mechanism. My goal was to ensure that no pending internal lock are open. Unfortunately there is no "ReadLockCount" or "WriteLockCount" to check that. I was considering a kind of "Flush" for all open locks, I thought the TMultiReadExclusiveWriteSynchronizer is doing something like that destructor TMultiReadExclusiveWriteSynchronizer.Destroy; begin BeginWrite; inherited Destroy; CloseHandle(FReadSignal); CloseHandle(FWriteSignal); tls.Free; end; Is calling BeginWrite maybe recommended to assure issues with open locks ? Of course it would create a lock, instead of closing. The TLightweightMREW has Initialize, but no according Finalize. class operator Initialize And even if so, would the Finalize be reliable called on class destruction, never checked that with CustomManagedRecords ( I hope it would ) ? I used to track locks with each successful TryBeginRead/EndRead, if needed, inside the class, by accounting with TInterlocked counters. But wouldn't it be better if the locking class/record itself would have offered its internal accounting. Probably there is something wrong with accounting of locks at all ( I know after the moment I've got a count, its all can be changed ) ? For just waiting until all is cleaned up before class destruction, or at least for preparing a clear error message "Hanging lock". Edited April 14, 2021 by Rollo62 Share this post Link to post
Stefan Glienke 2002 Posted April 14, 2021 (edited) 51 minutes ago, Rollo62 said: And even if so, would the Finalize be reliable called on class destruction? If you mean object destruction when you write class destruction, then yes. On Windows you can simply put an Assert(Pointer(lock) = nil) because when it does not hold any lock, then its 0. On other platforms you have to check the documentation of the posix API being used. You can even count the number of readlocks or if there is a write lock - they both set specific bits. Edited April 14, 2021 by Stefan Glienke Share this post Link to post