using System; using Implab.Parallels; using System.Threading; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; namespace Implab.Components { /// /// The base class for implementing thread-safe pools of disposable objects. /// /// /// This class maintains a set of pre-created objects which are frequently allocated and released /// by clients. The pool maintains maximum number of unsued object, any object above this limit is disposed, /// if the pool is empty it will create new objects on demand. /// Instances of this class are thread-safe. /// public abstract class DisposablePool : IDisposable { readonly int m_size; readonly AsyncQueue m_queue = new AsyncQueue(); [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 { var disposable = instance as IDisposable; if (disposable != null) disposable.Dispose(); } } protected virtual void Dispose(bool disposing) { if (disposing) { m_disposed = true; T instance; while (m_queue.TryDequeue(out instance)) { var disposable = instance as IDisposable; if (disposable != null) disposable.Dispose(); } } } #region IDisposable implementation public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } #endregion } }