Mercurial > pub > ImplabNet
comparison Implab/ObjectPool.cs @ 117:8beee0d11de6 v2
pool refactoring
| author | cin |
|---|---|
| date | Tue, 23 Dec 2014 19:48:47 +0300 |
| parents | cdaaf4792c22 |
| children | 2573b562e328 |
comparison
equal
deleted
inserted
replaced
| 116:da56ba7b1aab | 117:8beee0d11de6 |
|---|---|
| 1 using System; | 1 using Implab.Parallels; |
| 2 using Implab.Parallels; | 2 using System; |
| 3 using System.Threading; | 3 using System.Threading; |
| 4 using System.Diagnostics; | |
| 5 using System.Diagnostics.CodeAnalysis; | |
| 6 | 4 |
| 7 namespace Implab { | 5 namespace Implab { |
| 8 public abstract class ObjectPool<T> : IDisposable { | 6 /// <summary> |
| 7 /// Базовый класс для создания пулов объектов. | |
| 8 /// </summary> | |
| 9 /// <remarks> | |
| 10 /// <para>Пул объектов позволяет многократно использовать один и тотже объект, | |
| 11 /// что актуально для объектов, создание которых требует существенных ресурсов. | |
| 12 /// Пул объектов использует слабые ссылки, чтобы не препятствовать освобождению | |
| 13 /// ресурсов и создает новые объекты при необходимости.</para> | |
| 14 /// <para> | |
| 15 /// Наследники должны реализовывать метод <see cref="CreateInstance()"/> для создания | |
| 16 /// новых экземпляров. | |
| 17 /// </para> | |
| 18 /// <para>Пул поддерживает обращения сразу из нескольких потоков.</para> | |
| 19 /// </remarks> | |
| 20 public abstract class ObjectPool<T> where T : class { | |
| 21 readonly MTQueue<WeakReference> m_queue = new MTQueue<WeakReference>(); | |
| 9 readonly int m_size; | 22 readonly int m_size; |
| 10 readonly MTQueue<T> m_queue = new MTQueue<T>(); | 23 int m_count = 0; |
| 11 | 24 |
| 12 [SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes")] | 25 protected ObjectPool() : this(Environment.ProcessorCount+1) { |
| 13 static readonly bool _isValueType = typeof(T).IsValueType; | |
| 14 | 26 |
| 15 bool m_disposed; | 27 } |
| 16 | |
| 17 int m_count; | |
| 18 | 28 |
| 19 protected ObjectPool(int size) { | 29 protected ObjectPool(int size) { |
| 30 Safe.ArgumentInRange(size,1,size,"size"); | |
| 31 | |
| 20 m_size = size; | 32 m_size = size; |
| 21 } | |
| 22 | |
| 23 protected ObjectPool() : this(Environment.ProcessorCount+1) { | |
| 24 } | |
| 25 | |
| 26 public T Allocate() { | |
| 27 if (m_disposed) | |
| 28 throw new ObjectDisposedException(ToString()); | |
| 29 | |
| 30 T instance; | |
| 31 if (m_queue.TryDequeue(out instance)) { | |
| 32 Interlocked.Decrement(ref m_count); | |
| 33 } else { | |
| 34 instance = CreateInstance(); | |
| 35 Debug.Assert(!Object.Equals(instance, default(T)) || _isValueType); | |
| 36 } | |
| 37 return instance; | |
| 38 } | 33 } |
| 39 | 34 |
| 40 protected abstract T CreateInstance(); | 35 protected abstract T CreateInstance(); |
| 41 | 36 |
| 42 protected virtual void CleanupInstance(T instance) { | 37 protected virtual void CleanupInstance(T instance) { |
| 43 } | 38 } |
| 44 | 39 |
| 40 public T Allocate() { | |
| 41 WeakReference reference; | |
| 42 while (m_queue.TryDequeue(out reference)) { | |
| 43 Interlocked.Decrement(ref m_count); | |
| 44 object instance = reference.Target; | |
| 45 if (instance == null) | |
| 46 continue; | |
| 47 return (T)instance; | |
| 48 } | |
| 49 return CreateInstance(); | |
| 50 } | |
| 51 | |
| 45 public void Release(T instance) { | 52 public void Release(T instance) { |
| 46 if ( Object.Equals(instance,default(T)) && !_isValueType) | 53 if (m_count < m_size && instance != null) { |
| 47 return; | |
| 48 | |
| 49 Thread.MemoryBarrier(); | |
| 50 if (m_count < m_size && !m_disposed) { | |
| 51 Interlocked.Increment(ref m_count); | 54 Interlocked.Increment(ref m_count); |
| 52 | |
| 53 CleanupInstance(instance); | 55 CleanupInstance(instance); |
| 54 | 56 m_queue.Enqueue(new WeakReference(instance)); |
| 55 m_queue.Enqueue(instance); | |
| 56 | |
| 57 // пока элемент возвращался в кеш, была начата операция освобождения всего кеша | |
| 58 // и возможно уже законцена, в таком случае следует извлечь элемент обратно и | |
| 59 // освободить его. Если операция освобождения кеша еще не заврешилась, то будет | |
| 60 // изъят и освобожден произвольный элемен, что не повлияет на ход всего процесса. | |
| 61 if (m_disposed && m_queue.TryDequeue(out instance) && instance is IDisposable) | |
| 62 ((IDisposable)instance).Dispose() ; | |
| 63 | |
| 64 } else { | |
| 65 if (instance is IDisposable) | |
| 66 ((IDisposable)instance).Dispose(); | |
| 67 } | 57 } |
| 68 } | 58 } |
| 69 | |
| 70 protected virtual void Dispose(bool disposing) { | |
| 71 if (disposing) { | |
| 72 m_disposed = true; | |
| 73 T instance; | |
| 74 while (m_queue.TryDequeue(out instance)) | |
| 75 if (instance is IDisposable) | |
| 76 ((IDisposable)instance).Dispose(); | |
| 77 } | |
| 78 } | |
| 79 | |
| 80 #region IDisposable implementation | |
| 81 | |
| 82 public void Dispose() { | |
| 83 Dispose(true); | |
| 84 GC.SuppressFinalize(this); | |
| 85 } | |
| 86 | |
| 87 #endregion | |
| 88 } | 59 } |
| 89 } | 60 } |
| 90 |
