Mercurial > pub > ImplabNet
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; // сервис