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
+    }
+}
+