I think your algorithm has one "whole". Follow the scenario: Thread "W" begins the process of acquiring the "Write" lock. Somewhere around the "mov ECX,-1" it's time slice ends up. Thread "R" begins the process of acquiring the "Read" lock. If it gets past the "JS @@Spin" there's nothing to stop both threads from getting the lock. What's worst is that once the lock is acquired by both threads, the lock gets threshed. When the "W" threads finishes it's job it will set the value to "0". When the "R" threads finishes it will actually set the value to "-1". At this point the lock is locked for ever...
The "whole" comes from the fact you're using the spin lock for more than locking. Classic spin-lock algorithms use one fixed value for "locked" and one fixed value for "open", so it's guaranteed that only one thread will ever acquire the lock. In the locked exchange the classic spin-lock algorithm always writes the "LOCKED" value when it tries to acquire the lock. Next it can safely test for "UNLOCKED". If it didn't get "UNLOCKED" then it may safely loop on because it's guaranteed that it replaced "LOCKED" with "LOCKED" - so it did no harm. I think you should change your algorithm to use two separate variables: one for the lock, one for the counter. Protect the "counter" with the "lock" so you're guaranteed increments work right and you don't trash a write lock. P.S: Why didn't you go with the TMultiReadExclusiveWriteSynchronizer? Note this is not a recommendation to use that, I have no idea how efficient it actually is - I just know it's there and it does what you need. -- Cosmin Prund > -----Original Message----- > From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On > Behalf Of Wu Adam > Sent: Monday, June 04, 2007 10:16 AM > To: [email protected] > Subject: Re: Interface reference counting threadsafety > > I've written a very lightweight read-write spin lock, just for > protecting interface instances. > > I have put it in use in my program, and it seems working fine. > But I am not sure if it really works, becuase I have not yet > experienced this hypothetical race condition even without any > synchronization... > (most likely becuase I don't have a dual-core cpu...) > > If anyone got some free time, please help me bug check it. > > AdamWu > > (*** Start of code ***) > > // Simple Multi-read Exclusive-write spin lock > // NOTE: This object is designed to synchronize VERY VERY small > pieces of code. > // For efficiency reason, it does not have much error > correction > capability. > // HOW IT WORKS: It basically keeps track of the number of reader > thread by > // the (positive) value of an integer; and the writer thread > by > setting > // the integer to -1. > TRWSpinLock = Class > Private > rSyncInt: Integer; > > Public > Constructor Create; > Destructor Destroy; Override; > > Class Procedure ReadSync(Var SyncInt: Integer); Overload; > Register; > Class Procedure WriteSync(Var SyncInt: Integer); Overload; > Register; > Class Procedure ReadDone(Var SyncInt: Integer); Overload; > Register; > Class Procedure WriteDone(Var SyncInt: Integer); Overload; > Register; > Procedure ReadSync; Overload; Inline; > Procedure WriteSync; Overload; Inline; > Procedure ReadDone; Overload; Inline; > Procedure WriteDone; Overload; Inline; > END; > > Class Procedure TRWSpinLock.ReadSync(Var SyncInt: Integer); > { @SyncInt: EDX } > ASM > @@Back: > MOV EAX, [ SyncInt ] > TEST EAX, EAX > JS @@Spin > > MOV ECX, EAX > INC ECX > LOCK CMPXCHG [ SyncInt ], ECX > JZ @@Done > > @@Spin: > PAUSE > JMP @@Back > > @@Done: > END; > > Class Procedure TRWSpinLock.WriteSync(Var SyncInt: Integer); > { @SyncInt: EDX } > ASM > @@Back: > MOV EAX, [ SyncInt ] > TEST EAX, EAX > JNZ @@Spin > > MOV ECX, -1 > LOCK CMPXCHG [ SyncInt ], ECX > JZ @@Done > > @@Spin: > PAUSE > JMP @@Back > > @@Done: > END; > > Class Procedure TRWSpinLock.ReadDone(Var SyncInt: Integer); > { @SyncInt: EDX } > ASM > MOV EAX, -1 > LOCK XADD [ SyncInt ], EAX > END; > > Class Procedure TRWSpinLock.WriteDone(Var SyncInt: Integer); > { @SyncInt: EDX } > ASM > XOR EAX, EAX > LOCK XCHG [ SyncInt ], EAX > END; > > Constructor TRWSpinLock.Create; > BEGIN > Inherited; > > //rSyncInt:= 0; > END; > > Destructor TRWSpinLock.Destroy; > BEGIN > WriteSync; > > Inherited; > END; > > Procedure TRWSpinLock.ReadSync; > BEGIN > ReadSync(rSyncInt); > END; > > Procedure TRWSpinLock.WriteSync; > BEGIN > WriteSync(rSyncInt); > END; > > Procedure TRWSpinLock.ReadDone; > BEGIN > ReadDone(rSyncInt); > END; > > Procedure TRWSpinLock.WriteDone; > BEGIN > WriteDone(rSyncInt); > END; > > (*** End of code ***) > > To use the spinlock to protect interface instances: > * This class has ability to sync on both enternal and internal counters > For external counters, it is your responsibility to initialize it to > zero, > and make sure it does not get clobbered while used for sync purposes. > > * Use Read__() when making new references; > > Example: > > TRWSpinLock.ReadSync(RWCounter); > NewIntf:= ProtectedIntf; > TRWSpinLock.ReadDone; > > * Use Write__() when releasing references; > > TRWSpinLock.WriteSync(RWCounter); > ProtectedIntf:= NIL; > TRWSpinLock.WriteDone; > > * There are no support for transition between "read" and "write". > * Don't EVER mix and match __Sync() and __Done() calls. > > ------ > .dlrow eht htiw thgir s'lla ,nevaeh sih ni si doG > > _________________________________________________________________ > 享用世界上最大的电子邮件系统― MSN Hotmail。 http://www.hotmail.com
_______________________________________________ Delphi mailing list -> [email protected] http://www.elists.org/mailman/listinfo/delphi

