Skip to content

Commit 3f8bb02

Browse files
author
Oren (electricessence)
committed
Refactored to use ConcurrentQueue instead of ConcurrentBag
1 parent 4d1b110 commit 3f8bb02

2 files changed

Lines changed: 24 additions & 20 deletions

File tree

Open.Threading.ReadWrite.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<Description>Useful set of extensions and classes for simplifying and optimizing read-write synchronization.
1212

1313
Part of the "Open" set of libraries.</Description>
14-
<Version>1.0.1</Version>
14+
<Version>1.0.2</Version>
1515
<AssemblyVersion>1.0.0.1</AssemblyVersion>
1616
<FileVersion>1.0.0.1</FileVersion>
1717
<PackageTags>dotnet, dotnet-core, dotnetcore, cs, collections, extensions, threadsafe, thread-safe, readwrite, read-write, readerwriterlock, readerwriterlockslim</PackageTags>

ReadWriteHelper.cs

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)