|
|
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>();
|
|
|
|
|
|
volatile bool m_disposed;
|
|
|
|
|
|
volatile int m_count;
|
|
|
|
|
|
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) {
|
|
|
}
|
|
|
|
|
|
public ObjectPoolWrapper<T> Allocate() {
|
|
|
if (m_disposed)
|
|
|
throw new ObjectDisposedException(this.ToString());
|
|
|
|
|
|
T instance;
|
|
|
if (m_queue.TryDequeue(out instance)) {
|
|
|
Interlocked.Decrement(ref m_count);
|
|
|
return instance;
|
|
|
} else {
|
|
|
instance = m_factory();
|
|
|
}
|
|
|
return new ObjectPoolWrapper<T>(instance, this);
|
|
|
}
|
|
|
|
|
|
public void Release(T instance) {
|
|
|
if (m_count < m_size && !m_disposed) {
|
|
|
Interlocked.Increment(ref m_count);
|
|
|
|
|
|
if (m_cleanup != null)
|
|
|
m_cleanup(instance);
|
|
|
|
|
|
m_queue.Enqueue(instance);
|
|
|
|
|
|
// пока элемент возвращался в кеш, была начата операция освобождения всего кеша
|
|
|
// и возможно уже законцена, в таком случае следует извлечь элемент обратно и
|
|
|
// освободить его. Если операция освобождения кеша еще не заврешилась, то будет
|
|
|
// изъят и освобожден произвольный элемен, что не повлияет на ход всего процесса.
|
|
|
if (m_disposed && m_queue.TryDequeue(out instance))
|
|
|
Safe.Dispose(instance);
|
|
|
|
|
|
} else {
|
|
|
Safe.Dispose(instance);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
protected virtual void Dispose(bool disposing) {
|
|
|
if (disposing) {
|
|
|
m_disposed = true;
|
|
|
T instance;
|
|
|
while (m_queue.TryDequeue(out instance))
|
|
|
Safe.Dispose(instance);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
#region IDisposable implementation
|
|
|
|
|
|
public void Dispose() {
|
|
|
Dispose(true);
|
|
|
GC.SuppressFinalize(this);
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|