|
|
using Implab.Parallels;
|
|
|
using System;
|
|
|
using System.Threading;
|
|
|
|
|
|
namespace Implab.Components {
|
|
|
/// <summary>
|
|
|
/// Базовый класс для создания пулов объектов.
|
|
|
/// </summary>
|
|
|
/// <remarks>
|
|
|
/// <para>Пул объектов позволяет многократно использовать один и тотже объект,
|
|
|
/// что актуально для объектов, создание которых требует существенных ресурсов.
|
|
|
/// Пул объектов использует слабые ссылки, чтобы не препятствовать освобождению
|
|
|
/// ресурсов и создает новые объекты при необходимости.</para>
|
|
|
/// <para>
|
|
|
/// Наследники должны реализовывать метод <see cref="CreateInstance()"/> для создания
|
|
|
/// новых экземпляров.
|
|
|
/// </para>
|
|
|
/// <para>Пул поддерживает обращения сразу из нескольких потоков.</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,1,size,"size");
|
|
|
|
|
|
m_size = size;
|
|
|
}
|
|
|
|
|
|
protected abstract T CreateInstance();
|
|
|
|
|
|
protected virtual void CleanupInstance(T instance) {
|
|
|
}
|
|
|
|
|
|
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();
|
|
|
}
|
|
|
|
|
|
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));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|