Skip to content
This repository has been archived by the owner on May 21, 2022. It is now read-only.

Commit

Permalink
buffer.
Browse files Browse the repository at this point in the history
  • Loading branch information
pomma89 committed Apr 2, 2017
1 parent 787a509 commit 3e10e53
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 39 deletions.
79 changes: 57 additions & 22 deletions src/CodeProject.ObjectPool/Core/PooledObjectBuffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
/// </typeparam>
public sealed class PooledObjectBuffer<T>
public sealed class PooledObjectBuffer<T> : IEnumerable<T>
where T : PooledObject
{
#if (NET35 || NET40)
private const MethodImplOptions TryToInline = default(MethodImplOptions);
#else
private const MethodImplOptions TryToInline = MethodImplOptions.AggressiveInlining;
#endif

/// <summary>
/// Used as default value for <see cref="_pooledObjects"/>.
/// </summary>
Expand All @@ -48,48 +56,59 @@ public sealed class PooledObjectBuffer<T>
/// </summary>
private T[] _pooledObjects = NoObjects;

/// <summary>
/// The maximum capacity of this buffer.
/// </summary>
public int Capacity => _pooledObjects.Length;

/// <summary>
/// The number of items stored in this buffer.
/// </summary>
public int Count
{
get
{
var count = 0;
for (var i = 0; i < _pooledObjects.Length; ++i)
{
if (_pooledObjects[i] != null)
{
count++;
}
if (_pooledObjects[i] != null) count++;
}
return count;
}
}

/// <summary>
/// All objects currently stored inside the pool.
/// Returns an enumerator that iterates through the collection.
/// </summary>
protected IEnumerable<T> PooledObjects
/// <returns>An enumerator that can be used to iterate through the collection.</returns>
public IEnumerator<T> 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;
}
}
}

/// <summary>
/// Returns an enumerator that iterates through a collection.
/// </summary>
/// <returns>
/// An <see cref="IEnumerator"/> object that can be used to iterate through the collection.
/// </returns>
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;
Expand All @@ -99,48 +118,64 @@ 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;
}
}
return false;
}

public void Resize(int newCapacity)
/// <summary>
/// Resizes the buffer so that it fits to given capacity. If new capacity is smaller than
/// current capacity, then exceeding items are returned.
/// </summary>
/// <param name="newCapacity">The new capacity of this buffer.</param>
/// <returns>All exceeding items.</returns>
public IList<T> 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<T> exceedingItems = NoObjects;
if (currentCapacity > newCapacity)
{
for (var i = newCapacity; i < currentCapacity; ++i)
{
ref var item = ref _pooledObjects[i];
if (item != null)
{
item.Dispose();
if (exceedingItems == NoObjects)
{
exceedingItems = new List<T> { item };
}
else
{
exceedingItems.Add(item);
}
item = null;
}
}
}

Array.Resize(ref _pooledObjects, newCapacity);
return exceedingItems;
}
}
}
31 changes: 14 additions & 17 deletions src/CodeProject.ObjectPool/ObjectPool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}

/// <summary>
/// Gets the count of the objects currently in the pool.
/// </summary>
public int ObjectsInPoolCount => _pooledObjects.Count;
public int ObjectsInPoolCount => PooledObjects.Count;

/// <summary>
/// The concurrent buffer containing pooled objects.
/// </summary>
protected PooledObjectBuffer<T> _pooledObjects { get; } = new PooledObjectBuffer<T>();
protected PooledObjectBuffer<T> PooledObjects { get; } = new PooledObjectBuffer<T>();

#endregion Public Properties

Expand Down Expand Up @@ -156,8 +160,8 @@ public ObjectPool(int maximumPoolSize, Func<T> factoryMethod)
/// </summary>
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);
}
Expand All @@ -169,23 +173,16 @@ public void Clear()
/// <returns>A monitored object from the pool.</returns>
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();
}

Expand Down Expand Up @@ -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)
{
Expand Down

0 comments on commit 3e10e53

Please sign in to comment.