You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Zero/ZeroLevel/Services/MemoryPools/DefaultObjectPool.cs

102 lines
3.7 KiB

using System;
using System.Runtime.CompilerServices;
using System.Threading;
/*https://github.com/dotnet/aspnetcore/blob/main/src/ObjectPool*/
namespace MemoryPools
{
/// <summary>
/// Default implementation of <see cref="ObjectPool{T}"/>.
/// </summary>
/// <typeparam name="T">The type to pool objects for.</typeparam>
/// <remarks>This implementation keeps a cache of retained objects. This means that if objects are returned when the pool has already reached "maximumRetained" objects they will be available to be Garbage Collected.</remarks>
public class DefaultObjectPool<T> : ObjectPool<T> where T : class
{
private protected readonly ObjectWrapper[] _items;
private protected readonly IPooledObjectPolicy<T> _policy;
private protected readonly bool _isDefaultPolicy;
private protected T? _firstItem;
// This class was introduced in 2.1 to avoid the interface call where possible
private protected readonly PooledObjectPolicy<T>? _fastPolicy;
/// <summary>
/// Creates an instance of <see cref="DefaultObjectPool{T}"/>.
/// </summary>
/// <param name="policy">The pooling policy to use.</param>
public DefaultObjectPool(IPooledObjectPolicy<T> policy)
: this(policy, Environment.ProcessorCount * 2)
{
}
/// <summary>
/// Creates an instance of <see cref="DefaultObjectPool{T}"/>.
/// </summary>
/// <param name="policy">The pooling policy to use.</param>
/// <param name="maximumRetained">The maximum number of objects to retain in the pool.</param>
public DefaultObjectPool(IPooledObjectPolicy<T> policy, int maximumRetained)
{
_policy = policy ?? throw new ArgumentNullException(nameof(policy));
_fastPolicy = policy as PooledObjectPolicy<T>;
_isDefaultPolicy = IsDefaultPolicy();
// -1 due to _firstItem
_items = new ObjectWrapper[maximumRetained - 1];
bool IsDefaultPolicy()
{
var type = policy.GetType();
return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(DefaultPooledObjectPolicy<>);
}
}
/// <inheritdoc />
public override T Get()
{
var item = _firstItem;
if (item == null || Interlocked.CompareExchange(ref _firstItem, null, item) != item)
{
var items = _items;
for (var i = 0; i < items.Length; i++)
{
item = items[i].Element;
if (item != null && Interlocked.CompareExchange(ref items[i].Element, null, item) == item)
{
return item;
}
}
item = Create();
}
return item;
}
// Non-inline to improve its code quality as uncommon path
[MethodImpl(MethodImplOptions.NoInlining)]
private T Create() => _fastPolicy?.Create() ?? _policy.Create();
/// <inheritdoc />
public override void Return(T obj)
{
if (_isDefaultPolicy || (_fastPolicy?.Return(obj) ?? _policy.Return(obj)))
{
if (_firstItem != null || Interlocked.CompareExchange(ref _firstItem, obj, null) != null)
{
var items = _items;
for (var i = 0; i < items.Length && Interlocked.CompareExchange(ref items[i].Element, obj, null) != null; ++i)
{
}
}
}
}
private protected struct ObjectWrapper
{
public T? Element;
}
}
}

Powered by TurnKey Linux.