|
|
using Implab.Parallels;
|
|
|
using System;
|
|
|
using System.Threading;
|
|
|
|
|
|
namespace Implab.Components {
|
|
|
/// <summary>
|
|
|
/// The base class for creating object pools.
|
|
|
/// </summary>
|
|
|
/// <remarks>
|
|
|
/// <para>The objects pool is offers frequently requested objects to be reused, this gives
|
|
|
/// a gool speed improvement for the 'heavy' objects. To avoid memory overhead the pool uses
|
|
|
/// weak references allowing CG to do it's work. If there are no free objects in the pool
|
|
|
/// they are created on demand. </para>
|
|
|
/// <para>
|
|
|
/// Implementors need to defined a <see cref="CreateInstance()"/> method
|
|
|
/// </para>
|
|
|
/// <para>The instances of this class are thred-safe.</para>
|
|
|
/// </remarks>
|
|
|
public abstract class ObjectPool<T> where T : class {
|
|
|
readonly AsyncQueue<WeakReference> m_queue = new AsyncQueue<WeakReference>();
|
|
|
readonly int m_size;
|
|
|
int m_count = 0;
|
|
|
|
|
|
protected ObjectPool() : this(Environment.ProcessorCount+1) {
|
|
|
|
|
|
}
|
|
|
|
|
|
protected ObjectPool(int size) {
|
|
|
Safe.ArgumentInRange(size > 0, nameof(size));
|
|
|
|
|
|
m_size = size;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// Creates the instance if there are no free ones in the pool.
|
|
|
/// </summary>
|
|
|
/// <returns>The new instance.</returns>
|
|
|
protected abstract T CreateInstance();
|
|
|
|
|
|
/// <summary>
|
|
|
/// Cleanups the instance.
|
|
|
/// </summary>
|
|
|
/// <param name="instance">The instance to cleanup and prepare it for the next use.</param>
|
|
|
protected virtual void CleanupInstance(T instance) {
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// Allocate free instance from the pool or reates a new one.
|
|
|
/// </summary>
|
|
|
public T Allocate() {
|
|
|
WeakReference reference;
|
|
|
while (m_queue.TryDequeue(out reference)) {
|
|
|
Interlocked.Decrement(ref m_count);
|
|
|
object instance = reference.Target;
|
|
|
if (instance == null)
|
|
|
continue;
|
|
|
return (T)instance;
|
|
|
}
|
|
|
return CreateInstance();
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// Release the specified instance and returns it to the pool of free instances.
|
|
|
/// </summary>
|
|
|
/// <param name="instance">The instance to return to the pool.</param>
|
|
|
/// <remarks>Before the instance is returned to the pool the <see cref="CleanupInstance(T)"/> is called.</remarks>
|
|
|
public void Release(T instance) {
|
|
|
if (m_count < m_size && instance != null) {
|
|
|
Interlocked.Increment(ref m_count);
|
|
|
CleanupInstance(instance);
|
|
|
m_queue.Enqueue(new WeakReference(instance));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|