From 3e10e53071737274fa9dee04a0da4a42795ef070 Mon Sep 17 00:00:00 2001 From: Alessio Parma Date: Sun, 2 Apr 2017 14:19:00 +0200 Subject: [PATCH] buffer. --- .../Core/PooledObjectBuffer.cs | 79 +++++++++++++------ src/CodeProject.ObjectPool/ObjectPool.cs | 31 ++++---- 2 files changed, 71 insertions(+), 39 deletions(-) diff --git a/src/CodeProject.ObjectPool/Core/PooledObjectBuffer.cs b/src/CodeProject.ObjectPool/Core/PooledObjectBuffer.cs index 1590081..56fbd90 100644 --- a/src/CodeProject.ObjectPool/Core/PooledObjectBuffer.cs +++ b/src/CodeProject.ObjectPool/Core/PooledObjectBuffer.cs @@ -22,7 +22,9 @@ // OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. using System; +using System.Collections; using System.Collections.Generic; +using System.Runtime.CompilerServices; using System.Threading; namespace CodeProject.ObjectPool.Core @@ -35,9 +37,15 @@ namespace CodeProject.ObjectPool.Core /// The type of the object that which will be managed by the pool. The pooled object have to be /// a sub-class of PooledObject. /// - public sealed class PooledObjectBuffer + public sealed class PooledObjectBuffer : IEnumerable where T : PooledObject { +#if (NET35 || NET40) + private const MethodImplOptions TryToInline = default(MethodImplOptions); +#else + private const MethodImplOptions TryToInline = MethodImplOptions.AggressiveInlining; +#endif + /// /// Used as default value for . /// @@ -48,8 +56,14 @@ public sealed class PooledObjectBuffer /// private T[] _pooledObjects = NoObjects; + /// + /// The maximum capacity of this buffer. + /// public int Capacity => _pooledObjects.Length; + /// + /// The number of items stored in this buffer. + /// public int Count { get @@ -57,39 +71,44 @@ public int Count var count = 0; for (var i = 0; i < _pooledObjects.Length; ++i) { - if (_pooledObjects[i] != null) - { - count++; - } + if (_pooledObjects[i] != null) count++; } return count; } } /// - /// All objects currently stored inside the pool. + /// Returns an enumerator that iterates through the collection. /// - protected IEnumerable PooledObjects + /// An enumerator that can be used to iterate through the collection. + public IEnumerator GetEnumerator() { - get + for (var i = 0; i <= _pooledObjects.Length; ++i) { - for (var i = 0; i <= _pooledObjects.Length; ++i) + var item = _pooledObjects[i]; + if (item != null) { - var item = _pooledObjects[i]; - if (item != null) - { - yield return item; - } + yield return item; } } } + /// + /// Returns an enumerator that iterates through a collection. + /// + /// + /// An object that can be used to iterate through the collection. + /// + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + [MethodImpl(TryToInline)] public bool TryDequeue(out T pooledObject) { for (var i = 0; i < _pooledObjects.Length; i++) { - var item = _pooledObjects[i]; - if (item != null && Interlocked.CompareExchange(ref _pooledObjects[i], null, item) == item) + ref var itemRef = ref _pooledObjects[i]; + var item = itemRef; + if (item != null && Interlocked.CompareExchange(ref itemRef, null, item) == item) { pooledObject = item; return true; @@ -99,12 +118,13 @@ public bool TryDequeue(out T pooledObject) return false; } + [MethodImpl(TryToInline)] public bool TryEnqueue(T pooledObject) { for (var i = 0; i < _pooledObjects.Length; i++) { - ref var item = ref _pooledObjects[i]; - if (item == null && Interlocked.CompareExchange(ref item, pooledObject, null) == null) + ref var itemRef = ref _pooledObjects[i]; + if (itemRef == null && Interlocked.CompareExchange(ref itemRef, pooledObject, null) == null) { return true; } @@ -112,21 +132,28 @@ public bool TryEnqueue(T pooledObject) return false; } - public void Resize(int newCapacity) + /// + /// Resizes the buffer so that it fits to given capacity. If new capacity is smaller than + /// current capacity, then exceeding items are returned. + /// + /// The new capacity of this buffer. + /// All exceeding items. + public IList Resize(int newCapacity) { if (_pooledObjects == NoObjects) { _pooledObjects = new T[newCapacity]; - return; + return NoObjects; } var currentCapacity = _pooledObjects.Length; if (currentCapacity == newCapacity) { // Nothing to do. - return; + return NoObjects; } + IList exceedingItems = NoObjects; if (currentCapacity > newCapacity) { for (var i = newCapacity; i < currentCapacity; ++i) @@ -134,13 +161,21 @@ public void Resize(int newCapacity) ref var item = ref _pooledObjects[i]; if (item != null) { - item.Dispose(); + if (exceedingItems == NoObjects) + { + exceedingItems = new List { item }; + } + else + { + exceedingItems.Add(item); + } item = null; } } } Array.Resize(ref _pooledObjects, newCapacity); + return exceedingItems; } } } \ No newline at end of file diff --git a/src/CodeProject.ObjectPool/ObjectPool.cs b/src/CodeProject.ObjectPool/ObjectPool.cs index 24061ff..a5b4b64 100644 --- a/src/CodeProject.ObjectPool/ObjectPool.cs +++ b/src/CodeProject.ObjectPool/ObjectPool.cs @@ -59,26 +59,30 @@ public int MaximumPoolSize { get { - return _pooledObjects.Capacity; + return PooledObjects.Capacity; } set { // Preconditions Raise.ArgumentOutOfRangeException.If(value < 1, nameof(value), ErrorMessages.NegativeOrZeroMaximumPoolSize); - _pooledObjects.Resize(value); + // Resize the pool and destroy exceeding items, if any. + foreach (var exceedingItem in PooledObjects.Resize(value)) + { + DestroyPooledObject(exceedingItem); + } } } /// /// Gets the count of the objects currently in the pool. /// - public int ObjectsInPoolCount => _pooledObjects.Count; + public int ObjectsInPoolCount => PooledObjects.Count; /// /// The concurrent buffer containing pooled objects. /// - protected PooledObjectBuffer _pooledObjects { get; } = new PooledObjectBuffer(); + protected PooledObjectBuffer PooledObjects { get; } = new PooledObjectBuffer(); #endregion Public Properties @@ -156,8 +160,8 @@ public ObjectPool(int maximumPoolSize, Func factoryMethod) /// public void Clear() { - // Destroy all objects. - while (_pooledObjects.TryDequeue(out T dequeuedObjectToDestroy)) + // Destroy all objects, one by one. + while (PooledObjects.TryDequeue(out T dequeuedObjectToDestroy)) { DestroyPooledObject(dequeuedObjectToDestroy); } @@ -169,23 +173,16 @@ public void Clear() /// A monitored object from the pool. public T GetObject() { - if (_pooledObjects.TryDequeue(out T pooledObject)) + if (PooledObjects.TryDequeue(out T pooledObject)) { // Object found in pool. - if (Diagnostics.Enabled) - { - Diagnostics.IncrementPoolObjectHitCount(); - } + if (Diagnostics.Enabled) Diagnostics.IncrementPoolObjectHitCount(); } else { // This should not happen normally, but could be happening when there is stress on // the pool. No available objects in pool, create a new one and return it to the caller. - if (Diagnostics.Enabled) - { - Diagnostics.IncrementPoolObjectMissCount(); - } - + if (Diagnostics.Enabled) Diagnostics.IncrementPoolObjectMissCount(); pooledObject = CreatePooledObject(); } @@ -224,7 +221,7 @@ void IObjectPoolHandle.ReturnObjectToPool(PooledObject objectToReturnToPool, boo } // Trying to add the object back to the pool. - if (_pooledObjects.TryEnqueue(returnedObject)) + if (PooledObjects.TryEnqueue(returnedObject)) { if (Diagnostics.Enabled) {