view Implab/DisposablePool.cs @ 123:f4d6ea6969cc v2

async queue improvements
author cin
date Tue, 13 Jan 2015 01:42:38 +0300
parents 2573b562e328
children
line wrap: on
line source

using System;
using Implab.Parallels;
using System.Threading;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;

namespace Implab {
    public abstract class DisposablePool<T> : IDisposable {
        readonly int m_size;
        readonly AsyncQueue<T> m_queue = new AsyncQueue<T>();

        [SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes")]
        static readonly bool _isValueType = typeof(T).IsValueType;

        bool m_disposed;

        int m_count;

        protected DisposablePool(int size) {
            m_size = size;
        }

        protected DisposablePool() : this(Environment.ProcessorCount+1) {
        }

        public T Allocate() {
            if (m_disposed)
                throw new ObjectDisposedException(ToString());

            T instance;
            if (m_queue.TryDequeue(out instance)) {
                Interlocked.Decrement(ref m_count);
            } else {
                instance = CreateInstance();
                Debug.Assert(!Object.Equals(instance, default(T)) || _isValueType);
            }
            return instance;
        }

        protected abstract T CreateInstance();

        protected virtual void CleanupInstance(T instance) {
        }

        public void Release(T instance) {
            if ( Object.Equals(instance,default(T)) && !_isValueType)
                return;

            Thread.MemoryBarrier();
            if (m_count < m_size && !m_disposed) {
                Interlocked.Increment(ref m_count);

                CleanupInstance(instance);

                m_queue.Enqueue(instance);

                // пока элемент возвращался в кеш, была начата операция освобождения всего кеша
                // и возможно уже законцена, в таком случае следует извлечь элемент обратно и
                // освободить его. Если операция освобождения кеша еще не заврешилась, то будет
                // изъят и освобожден произвольный элемен, что не повлияет на ход всего процесса.
                if (m_disposed && m_queue.TryDequeue(out instance) && instance is IDisposable)
                    ((IDisposable)instance).Dispose() ;

            } else {
                if (instance is IDisposable)
                    ((IDisposable)instance).Dispose();
            }
        }

        protected virtual void Dispose(bool disposing) {
            if (disposing) {
                m_disposed = true;
                T instance;
                while (m_queue.TryDequeue(out instance))
                    if (instance is IDisposable)
                        ((IDisposable)instance).Dispose();
            }
        }

        #region IDisposable implementation

        public void Dispose() {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        #endregion
    }
}