@@ -23,7 +23,7 @@ public class ReadWriteHelper<TKey> : DeferredCleanupBase
2323
2424 private class ReaderWriterLockTracker : DisposableBase
2525 {
26- readonly List < object > _registry = new List < object > ( ) ;
26+ readonly HashSet < object > _registry = new HashSet < object > ( ) ;
2727
2828 internal ReaderWriterLockSlim Lock ;
2929
@@ -43,23 +43,27 @@ public bool Reserve(object context)
4343 return false ;
4444
4545 lock ( _registry )
46- _registry . Add ( context ) ;
47-
48- return true ;
46+ {
47+ return _registry . Add ( context ) ;
48+ }
4949 }
5050
5151 public void Clear ( object context )
5252 {
5353 lock ( _registry )
54+ {
5455 _registry . Remove ( context ) ;
56+ }
5557 }
5658
5759 public bool CanDispose
5860 {
5961 get
6062 {
6163 lock ( _registry )
62- return ! _registry . Any ( ) ;
64+ {
65+ return _registry . Count == 0 ;
66+ }
6367 }
6468 }
6569
@@ -80,8 +84,8 @@ protected override void OnDispose(bool calledExplicitly)
8084 }
8185
8286
83- readonly ConcurrentBag < object > ContextPool = new ConcurrentBag < object > ( ) ;
84- readonly ConcurrentBag < ReaderWriterLockTracker > LockPool = new ConcurrentBag < ReaderWriterLockTracker > ( ) ;
87+ readonly ConcurrentQueue < object > ContextPool = new ConcurrentQueue < object > ( ) ;
88+ readonly ConcurrentQueue < ReaderWriterLockTracker > LockPool = new ConcurrentQueue < ReaderWriterLockTracker > ( ) ;
8589
8690 readonly ConcurrentDictionary < TKey , ReaderWriterLockTracker > Locks
8791 = new ConcurrentDictionary < TKey , ReaderWriterLockTracker > ( ) ;
@@ -136,7 +140,7 @@ private ReaderWriterLockTracker GetLock(TKey key, LockType type, object context,
136140 {
137141 result = Locks . GetOrAdd ( key , k =>
138142 {
139- if ( ! LockPool . TryTake ( out created ) )
143+ if ( ! LockPool . TryDequeue ( out created ) )
140144 {
141145 created = new ReaderWriterLockTracker ( RecursionPolicy ) ;
142146 if ( Debugger . IsAttached )
@@ -155,7 +159,7 @@ private ReaderWriterLockTracker GetLock(TKey key, LockType type, object context,
155159 if ( IsDisposed )
156160 created . Dispose ( ) ;
157161 else
158- LockPool . Add ( created ) ;
162+ LockPool . Enqueue ( created ) ;
159163 }
160164
161165 // This should never get out of sync, but just in case...
@@ -282,7 +286,7 @@ private bool Execute(TKey key, LockType type, Action<ReaderWriterLockSlim> closu
282286 throw new ArgumentNullException ( "closure" ) ;
283287 ReaderWriterLockSlimExensions . ValidateMillisecondsTimeout ( millisecondsTimeout ) ;
284288
285- if ( ! ContextPool . TryTake ( out object context ) || context == null )
289+ if ( ! ContextPool . TryDequeue ( out object context ) || context == null )
286290 context = new Object ( ) ;
287291
288292 ReaderWriterLockTracker rwlock = GetLock ( key , type , context , millisecondsTimeout , throwsOnTimeout ) ;
@@ -299,7 +303,7 @@ private bool Execute(TKey key, LockType type, Action<ReaderWriterLockSlim> closu
299303 {
300304 ReleaseLock ( rwlock . Lock , type ) ;
301305 rwlock . Clear ( context ) ;
302- ContextPool . Add ( context ) ;
306+ ContextPool . Enqueue ( context ) ;
303307 }
304308 catch ( Exception ex )
305309 {
@@ -661,7 +665,7 @@ private void CleanupInternal()
661665 {
662666 try
663667 {
664- LockPool . Add ( tempLock ) ;
668+ LockPool . Enqueue ( tempLock ) ;
665669 }
666670 catch ( ObjectDisposedException )
667671 {
@@ -685,14 +689,14 @@ protected void UpdateCleanupDelay()
685689 CleanupDelay = Math . Max ( Math . Min ( 1000000 / ( Locks . Count + 1 ) , 10000 ) , 1000 ) ; // Don't allow for less than.
686690 }
687691
688- private void ConcurrentBagTrim < T > ( ConcurrentBag < T > target , int maxCount = 0 , bool dispose = false , bool allowExceptions = true )
692+ private void TrimPool < T > ( ConcurrentQueue < T > target , int maxCount = 0 , bool dispose = false , bool allowExceptions = true )
689693 {
690694 if ( target == null )
691695 throw new ArgumentNullException ( "target" ) ;
692696 //var d = new List<IDisposable>();
693697 try
694698 {
695- while ( ! target . IsEmpty && target . Count > maxCount && target . TryTake ( out T context ) )
699+ while ( ! target . IsEmpty && target . Count > maxCount && target . TryDequeue ( out T context ) )
696700 {
697701 if ( dispose )
698702 {
@@ -738,8 +742,8 @@ protected override void OnCleanup()
738742 var count = Locks . Count ;
739743 var maxCount = Math . Min ( count , 100 ) ;
740744
741- ConcurrentBagTrim ( ContextPool , maxCount * 2 ) ;
742- ConcurrentBagTrim ( LockPool , maxCount , true ) ; //ConcurrentQueueTrimAndDispose(LockPool, maxCount);
745+ TrimPool ( ContextPool , maxCount * 2 ) ;
746+ TrimPool ( LockPool , maxCount , true ) ; //ConcurrentQueueTrimAndDispose(LockPool, maxCount);
743747
744748 if ( Debugger . IsAttached && LockPool . Any ( l => l . IsDisposed ) )
745749 Debug . Fail ( "LockPool is retaining a disposed tracker." ) ;
@@ -769,7 +773,7 @@ protected override void OnDispose(bool calledExplicitly)
769773
770774 CleanupInternal ( ) ;
771775 Locks . Clear ( ) ; // Some locks may be removed, but releasing will still occur.
772- ConcurrentBagTrim ( LockPool , 0 , true , calledExplicitly ) ;
776+ TrimPool ( LockPool , 0 , true , calledExplicitly ) ;
773777
774778 } , calledExplicitly ? 1000 : 0 ) ; // We don't want to block for any reason for too long.
775779 // Dispose shouldn't be called without this being able to be cleaned.
@@ -785,9 +789,9 @@ protected override void OnDispose(bool calledExplicitly)
785789
786790 Locks . Clear ( ) ;
787791
788- ConcurrentBagTrim ( ContextPool , 0 , false , calledExplicitly ) ;
792+ TrimPool ( ContextPool , 0 , false , calledExplicitly ) ;
789793 if ( ! lockHeld )
790- ConcurrentBagTrim ( LockPool , 0 , true , calledExplicitly ) ;
794+ TrimPool ( LockPool , 0 , true , calledExplicitly ) ;
791795
792796 if ( calledExplicitly && Debugger . IsAttached )
793797 {
0 commit comments