ObjectPool.cs
75 lines
| 2.7 KiB
| text/x-csharp
|
CSharpLexer
cin
|
r152 | using Implab.Parallels; | ||
using System; | ||||
using System.Threading; | ||||
namespace Implab.Components { | ||||
/// <summary> | ||||
cin
|
r154 | /// The base class for creating object pools. | ||
cin
|
r152 | /// </summary> | ||
/// <remarks> | ||||
cin
|
r154 | /// <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> | ||||
cin
|
r152 | /// <para> | ||
cin
|
r154 | /// Implementors need to defined a <see cref="CreateInstance()"/> method | ||
cin
|
r152 | /// </para> | ||
cin
|
r154 | /// <para>The instances of this class are thred-safe.</para> | ||
cin
|
r152 | /// </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) { | ||||
cin
|
r251 | Safe.ArgumentInRange(size > 0, nameof(size)); | ||
cin
|
r152 | |||
m_size = size; | ||||
} | ||||
cin
|
r154 | /// <summary> | ||
/// Creates the instance if there are no free ones in the pool. | ||||
/// </summary> | ||||
/// <returns>The new instance.</returns> | ||||
cin
|
r152 | protected abstract T CreateInstance(); | ||
cin
|
r154 | /// <summary> | ||
/// Cleanups the instance. | ||||
/// </summary> | ||||
/// <param name="instance">The instance to cleanup and prepare it for the next use.</param> | ||||
cin
|
r152 | protected virtual void CleanupInstance(T instance) { | ||
} | ||||
cin
|
r154 | /// <summary> | ||
/// Allocate free instance from the pool or reates a new one. | ||||
/// </summary> | ||||
cin
|
r152 | 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(); | ||||
} | ||||
cin
|
r154 | /// <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> | ||||
cin
|
r152 | 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)); | ||||
} | ||||
} | ||||
} | ||||
} | ||||