diff Implab/Components/ObjectPool.cs @ 152:240aa6994018 v2

component model refactoring
author cin
date Thu, 11 Feb 2016 01:56:27 +0300
parents
children 2dcdee4c0810
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab/Components/ObjectPool.cs	Thu Feb 11 01:56:27 2016 +0300
@@ -0,0 +1,60 @@
+using Implab.Parallels;
+using System;
+using System.Threading;
+
+namespace Implab.Components {
+    /// <summary>
+    /// Базовый класс для создания пулов объектов.
+    /// </summary>
+    /// <remarks>
+    /// <para>Пул объектов позволяет многократно использовать один и тотже объект,
+    /// что актуально для объектов, создание которых требует существенных ресурсов.
+    /// Пул объектов использует слабые ссылки, чтобы не препятствовать освобождению
+    /// ресурсов и создает новые объекты при необходимости.</para>
+    /// <para>
+    /// Наследники должны реализовывать метод <see cref="CreateInstance()"/> для создания
+    /// новых экземпляров.
+    /// </para>
+    /// <para>Пул поддерживает обращения сразу из нескольких потоков.</para>
+    /// </remarks>
+    public abstract class ObjectPool<T> where T : class {
+        readonly AsyncQueue<WeakReference> m_queue = new AsyncQueue<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));
+            }
+        }
+    }
+}