view Implab/Components/ObjectPool.cs @ 157:948c015a9011 v2

sync
author cin
date Thu, 18 Feb 2016 11:03:47 +0300
parents 2dcdee4c0810
children 7c7e9ad6fe4a
line wrap: on
line source

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,1,size,"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));
            }
        }
    }
}