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.
Using TMultiReadExclusiveWriteSynchronizer
a sizable amount of time is spent inside BeginRead
and EndRead
:
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.
TOmniMREW
from OmniThreadLibrary
claims to be faster and more lightweight:
OTL is an excellent threading lib, BTW.
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;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With