diff Implab/ObjectPool.cs @ 117:8beee0d11de6 v2

pool refactoring
author cin
date Tue, 23 Dec 2014 19:48:47 +0300
parents cdaaf4792c22
children 2573b562e328
line wrap: on
line diff
--- a/Implab/ObjectPool.cs	Tue Dec 23 03:20:39 2014 +0300
+++ b/Implab/ObjectPool.cs	Tue Dec 23 19:48:47 2014 +0300
@@ -1,90 +1,60 @@
-using System;
-using Implab.Parallels;
-using System.Threading;
-using System.Diagnostics;
-using System.Diagnostics.CodeAnalysis;
-
-namespace Implab {
-    public abstract class ObjectPool<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 ObjectPool(int size) {
-            m_size = size;
-        }
-
-        protected ObjectPool() : 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
-    }
-}
-
+using Implab.Parallels;
+using System;
+using System.Threading;
+
+namespace Implab {
+    /// <summary>
+    /// Базовый класс для создания пулов объектов.
+    /// </summary>
+    /// <remarks>
+    /// <para>Пул объектов позволяет многократно использовать один и тотже объект,
+    /// что актуально для объектов, создание которых требует существенных ресурсов.
+    /// Пул объектов использует слабые ссылки, чтобы не препятствовать освобождению
+    /// ресурсов и создает новые объекты при необходимости.</para>
+    /// <para>
+    /// Наследники должны реализовывать метод <see cref="CreateInstance()"/> для создания
+    /// новых экземпляров.
+    /// </para>
+    /// <para>Пул поддерживает обращения сразу из нескольких потоков.</para>
+    /// </remarks>
+    public abstract class ObjectPool<T> where T : class {
+        readonly MTQueue<WeakReference> m_queue = new MTQueue<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;
+        }
+
+        protected abstract T CreateInstance();
+
+        protected virtual void CleanupInstance(T instance) {
+        }
+
+        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();
+        }
+
+        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));
+            }
+        }
+    }
+}