Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Faster TMultiReadExclusiveWriteSynchronizer?

Tags:

Is there a faster kind of TMultiReadExclusiveWriteSynchronizer out there? FastCode perhaps?

Starting with Windows Vista, Microsoft added a Slim Reader/Writer lock. It performs much better than Delphi's TMultiReadExclusiveWriteSynchronizer. Unfortunately it only exists in Windows Vista and later, something which few customers actually have yet.

Presumably the concepts in use inside a Slim Reader/Writer lock could be redone in native Delphi code - but has anyone done it?

i have a situation where acquiring and releasing locks on a TMultiReadExclusiveWriteSynchronizer (even when there's no contention - a single thread), causes 100% overhead (the operation time doubles). i can run without locking, but then my class is no longer thread-safe.

Is there a faster TMultiReadExclusiveWriteSynchronizer?

Note: If i use a TCriticalSection i only suffer a 2% performance hit (although critical sections are known to be fast when the acquire succeeds, i.e. while it's single threaded and there's no contention). The downside of a CS is that i lose the "multiple readers" capability.

The Measurements

Using TMultiReadExclusiveWriteSynchronizer a sizable amount of time is spent inside BeginRead and EndRead:

enter image description here

i then ported the code to use Window's own SlimReaderWriter Lock (which some code rewrite, as it doesn't support recursive lock taking), and profiled the resutls:

  • TMultiReadExclusiveWriteSynchronizer: 10,698 ns per iteration
    10,697,772,613 ns to iterate 1,000,000 times

  • SRWLock: 8,802 ns per iteration
    8,801,678,339 ns to iterate 1,000,000 times

  • Omni Reader-Writer lock: 8,941 ns per iteration
    8,940,552,487 ns to iterate 1,000,000 times

A 17% improvement when using SRWLocks (aka Omni's spinning lock).

Now, i cannot switch the code permanantly over to use Windows Vista SRWLocks, as there are some entire enterprises of customers that are still on Windows XP.

The Slim locks are just careful use of InterlockedCompareExchange functions; but more careful than i can successfully use. I'm this far away from just stealing the 140 machine instructions involved, and have it done.

Bonus Reading

  • Is Critical Section always faster?
  • How to write fast multi-thread Delphi applications
like image 482
Ian Boyd Avatar asked Apr 30 '12 03:04

Ian Boyd


1 Answers

TOmniMREW from OmniThreadLibrary claims to be faster and more lightweight:

OTL is an excellent threading lib, BTW.

Sample Code

TOmniReaderWriterLock = class(TInterfacedObject, IReaderWriterLock) private    omrewReference: Integer; public    { IReaderWriterLock }    procedure BeginRead;    procedure EndRead;    procedure BeginWrite;    procedure EndWrite; end;  { TOmniReaderWriterLock }  procedure TOmniReaderWriterLock.BeginRead; var   currentReference: Integer; begin     //Wait on writer to reset write flag so Reference.Bit0 must be 0 than increase Reference     repeat         currentReference := Integer(omrewReference) and not 1;     until currentReference = Integer(InterlockedCompareExchange(Pointer(omrewReference), Pointer(Integer(currentReference) + 2), Pointer(currentReference))); end;  procedure TOmniReaderWriterLock.EndRead; begin     //Decrease omrewReference     InterlockedExchangeAdd(@omrewReference, -2); end;  procedure TOmniReaderWriterLock.BeginWrite; var     currentReference: integer; begin     //Wait on writer to reset write flag so omrewReference.Bit0 must be 0 then set omrewReference.Bit0     repeat         currentReference := omrewReference and (not 1);     until currentReference = Integer(InterlockedCompareExchange(Pointer(omrewReference), Pointer(currentReference+1), Pointer(currentReference)));      //Now wait on all readers     repeat     until omrewReference = 1; end;  procedure TOmniReaderWriterLock.EndWrite; begin     omrewReference := 0; end; 
like image 177
Edwin Yip Avatar answered Sep 20 '22 15:09

Edwin Yip