##// END OF EJS Templates
Merge
Merge

File last commit:

r256:c52691faaf21 v3
r283:d1498b67e01a merge default
Show More
DisposablePool.cs
102 lines | 3.6 KiB | text/x-csharp | CSharpLexer
using System;
using Implab.Parallels;
using System.Threading;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
namespace Implab.Components {
/// <summary>
/// The base class for implementing pools of disposable objects.
/// </summary>
/// <remarks>
/// <para>This class maintains a set of pre-created objects and which are frequently allocated and released
/// by clients. The pool maintains maximum number of unsued object, any object above this limit is disposed,
/// if the pool is empty it will create new objects on demand.</para>
/// <para>Instances of this class are thread-safe.</para>
/// </remarks>
public abstract class DisposablePool<T> : IDisposable {
readonly int m_size;
readonly AsyncQueue<T> m_queue = new AsyncQueue<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 {
var disposable = instance as IDisposable;
if (disposable != null)
disposable.Dispose();
}
}
protected virtual void Dispose(bool disposing) {
if (disposing) {
m_disposed = true;
T instance;
while (m_queue.TryDequeue(out instance)) {
var disposable = instance as IDisposable;
if (disposable != null)
disposable.Dispose();
}
}
}
#region IDisposable implementation
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
}