diff Implab/Components/DisposablePool.cs @ 192:f1da3afc3521 release v2.1

Слияние с v2
author cin
date Fri, 22 Apr 2016 13:10:34 +0300
parents b933ec88446e
children c52691faaf21
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab/Components/DisposablePool.cs	Fri Apr 22 13:10:34 2016 +0300
@@ -0,0 +1,102 @@
+using System;
+using Implab.Parallels;
+using System.Threading;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+
+namespace Implab.Components {
+    /// <summary>
+    /// The base class for implementing pools of disposable objects.
+    /// </summary>
+    /// <remarks>
+    /// <para>This class maintains a set of pre-created objects and 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.</para>
+    /// <para>Instances of this class are thread-safe.</para>
+    /// </remarks>
+    public abstract class DisposablePool<T> : IDisposable {
+        readonly int m_size;
+        readonly AsyncQueue<T> m_queue = new AsyncQueue<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 {
+                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
+    }
+}
+