Mercurial > pub > ImplabNet
diff Implab/DisposablePool.cs @ 117:8beee0d11de6 v2
pool refactoring
author | cin |
---|---|
date | Tue, 23 Dec 2014 19:48:47 +0300 |
parents | |
children | 2573b562e328 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Implab/DisposablePool.cs Tue Dec 23 19:48:47 2014 +0300 @@ -0,0 +1,90 @@ +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 MTQueue<T> m_queue = new MTQueue<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 + } +} +