view Implab/ObjectPool.cs @ 143:16f926ee499d v2

DRAFT: refactoring, adding cancelation token
author cin
date Wed, 04 Mar 2015 18:05:39 +0300
parents 2573b562e328
children
line wrap: on
line source

using Implab.Parallels;
using System;
using System.Threading;

namespace Implab {
    /// <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));
            }
        }
    }
}