ObjectPool.cs
92 lines
| 3.1 KiB
| text/x-csharp
|
CSharpLexer
/ Implab / ObjectPool.cs
|
|
r82 | using System; | ||
| using Implab.Parallels; | ||||
| using System.Threading; | ||||
| namespace Implab { | ||||
| public class ObjectPool<T> : IDisposable { | ||||
| readonly Func<T> m_factory; | ||||
| readonly Action<T> m_cleanup; | ||||
| readonly int m_size; | ||||
| readonly MTQueue<T> m_queue = new MTQueue<T>(); | ||||
|
|
r83 | bool m_disposed; | ||
|
|
r82 | |||
|
|
r83 | int m_count; | ||
|
|
r82 | |||
| public ObjectPool(Func<T> factory, Action<T> cleanup, int size) { | ||||
| Safe.ArgumentNotNull(factory, "factory"); | ||||
| Safe.ArgumentInRange(size, 1, size, "size"); | ||||
| m_factory = factory; | ||||
| m_cleanup = cleanup; | ||||
| m_size = size; | ||||
| } | ||||
| public ObjectPool(Func<T> factory, Action<T> cleanup) : this(factory,cleanup,Environment.ProcessorCount+1) { | ||||
| } | ||||
| public ObjectPool(Func<T> factory) : this(factory,null,Environment.ProcessorCount+1) { | ||||
| } | ||||
|
|
r83 | public ObjectPoolWrapper<T> AllocateAuto() { | ||
| return new ObjectPoolWrapper<T>(Allocate(), this); | ||||
| } | ||||
| public T Allocate() { | ||||
|
|
r82 | if (m_disposed) | ||
| throw new ObjectDisposedException(this.ToString()); | ||||
| T instance; | ||||
| if (m_queue.TryDequeue(out instance)) { | ||||
| Interlocked.Decrement(ref m_count); | ||||
| } else { | ||||
| instance = m_factory(); | ||||
| } | ||||
|
|
r83 | return instance; | ||
|
|
r82 | } | ||
| public void Release(T instance) { | ||||
|
|
r83 | Thread.MemoryBarrier(); | ||
|
|
r82 | if (m_count < m_size && !m_disposed) { | ||
| Interlocked.Increment(ref m_count); | ||||
| if (m_cleanup != null) | ||||
| m_cleanup(instance); | ||||
| m_queue.Enqueue(instance); | ||||
| // пока элемент возвращался в кеш, была начата операция освобождения всего кеша | ||||
| // и возможно уже законцена, в таком случае следует извлечь элемент обратно и | ||||
| // освободить его. Если операция освобождения кеша еще не заврешилась, то будет | ||||
| // изъят и освобожден произвольный элемен, что не повлияет на ход всего процесса. | ||||
|
|
r83 | if (m_disposed && m_queue.TryDequeue(out instance) && instance is IDisposable) | ||
| ((IDisposable)instance).Dispose() ; | ||||
|
|
r82 | |||
| } else { | ||||
|
|
r83 | if (instance is IDisposable) | ||
| ((IDisposable)instance).Dispose(); | ||||
|
|
r82 | } | ||
| } | ||||
| protected virtual void Dispose(bool disposing) { | ||||
| if (disposing) { | ||||
| m_disposed = true; | ||||
| T instance; | ||||
| while (m_queue.TryDequeue(out instance)) | ||||
|
|
r83 | if (instance is IDisposable) | ||
| ((IDisposable)instance).Dispose(); | ||||
|
|
r82 | } | ||
| } | ||||
| #region IDisposable implementation | ||||
| public void Dispose() { | ||||
| Dispose(true); | ||||
| GC.SuppressFinalize(this); | ||||
| } | ||||
| #endregion | ||||
| } | ||||
| } | ||||
