view Implab/Components/ObjectPool.cs @ 196:40d7fed4a09e

fixed promise chaining behavior, the error handler doesn't handle result or cancellation handlers exceptions these exceptions are propagated to the next handlers.
author cin
date Mon, 29 Aug 2016 23:15:51 +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));
            }
        }
    }
}