changeset 117:8beee0d11de6 v2

pool refactoring
author cin
date Tue, 23 Dec 2014 19:48:47 +0300
parents da56ba7b1aab
children e046a94eecb1
files Implab/DisposablePool.cs Implab/Implab.csproj Implab/ObjectPool.cs Implab/SafePool.cs Implab/ServiceLocator.cs
diffstat 5 files changed, 153 insertions(+), 133 deletions(-) [+]
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
+    }
+}
+
--- a/Implab/Implab.csproj	Tue Dec 23 03:20:39 2014 +0300
+++ b/Implab/Implab.csproj	Tue Dec 23 19:48:47 2014 +0300
@@ -127,7 +127,6 @@
     <Compile Include="Parsing\StarToken.cs" />
     <Compile Include="Parsing\SymbolToken.cs" />
     <Compile Include="Parsing\Token.cs" />
-    <Compile Include="SafePool.cs" />
     <Compile Include="ServiceLocator.cs" />
     <Compile Include="TaskController.cs" />
     <Compile Include="ProgressInitEventArgs.cs" />
@@ -139,7 +138,6 @@
     <Compile Include="PromiseExtensions.cs" />
     <Compile Include="TransientPromiseException.cs" />
     <Compile Include="SyncContextPromise.cs" />
-    <Compile Include="ObjectPool.cs" />
     <Compile Include="Diagnostics\OperationContext.cs" />
     <Compile Include="Diagnostics\TraceContext.cs" />
     <Compile Include="Diagnostics\LogEventArgs.cs" />
@@ -150,6 +148,8 @@
     <Compile Include="Parallels\MTCustomQueue.cs" />
     <Compile Include="Parallels\MTCustomQueueNode.cs" />
     <Compile Include="ComponentContainer.cs" />
+    <Compile Include="DisposablePool.cs" />
+    <Compile Include="ObjectPool.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <ItemGroup />
--- 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));
+            }
+        }
+    }
+}
--- a/Implab/SafePool.cs	Tue Dec 23 03:20:39 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-using Implab.Parallels;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading;
-
-namespace Implab {
-    public class SafePool<T> where T : new() {
-        readonly MTQueue<T> m_queue = new MTQueue<T>();
-        readonly int m_size;
-        int m_count = 0;
-
-        public SafePool() : this(10) {
-
-        }
-
-        public SafePool(int size) {
-            Safe.ArgumentInRange(size,1,size,"size");
-
-            m_size = size;
-        }
-
-        public T Allocate() {
-            T instance;
-            if (m_queue.TryDequeue(out instance)) {
-                Interlocked.Decrement(ref m_count);
-                return instance;
-            }
-            return new T();
-        }
-
-        public void Release(T instance) {
-            if (m_count < m_size) {
-                Interlocked.Increment(ref m_count);
-                m_queue.Enqueue(instance);
-            }
-        }
-    }
-}
--- a/Implab/ServiceLocator.cs	Tue Dec 23 03:20:39 2014 +0300
+++ b/Implab/ServiceLocator.cs	Tue Dec 23 19:48:47 2014 +0300
@@ -5,7 +5,7 @@
     /// <summary>
     /// Коллекция сервисов, позволяет регистрировать и получать сервисы.
     /// </summary>
-    public class ServiceLocator: Component, IServiceLocator, IServiceProvider {
+    public class ServiceLocator: Disposable, IServiceLocator, IServiceProvider {
         // запись о сервисе
         struct ServiceEntry : IDisposable {
             public object service; // сервис