Jump to content
Sign in to follow this  
Rollo62

TLightweightMREW considerations

Recommended Posts

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 by Rollo62

Share this post


Link to post

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

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
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 by Rollo62

Share this post


Link to post
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 by Stefan Glienke

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×