ObjectPool.cs
90 lines
| 3.0 KiB
| text/x-csharp
|
CSharpLexer
/ Implab / ObjectPool.cs
cin
|
r82 | using System; | ||
using Implab.Parallels; | ||||
using System.Threading; | ||||
cin
|
r85 | using System.Diagnostics; | ||
using System.Diagnostics.CodeAnalysis; | ||||
cin
|
r82 | |||
namespace Implab { | ||||
cin
|
r85 | public abstract class ObjectPool<T> : IDisposable { | ||
cin
|
r82 | readonly int m_size; | ||
readonly MTQueue<T> m_queue = new MTQueue<T>(); | ||||
cin
|
r85 | [SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes")] | ||
static readonly bool _isValueType = typeof(T).IsValueType; | ||||
cin
|
r83 | bool m_disposed; | ||
cin
|
r82 | |||
cin
|
r83 | int m_count; | ||
cin
|
r82 | |||
cin
|
r85 | protected ObjectPool(int size) { | ||
cin
|
r82 | m_size = size; | ||
} | ||||
cin
|
r85 | protected ObjectPool() : this(Environment.ProcessorCount+1) { | ||
cin
|
r82 | } | ||
cin
|
r83 | public T Allocate() { | ||
cin
|
r82 | if (m_disposed) | ||
cin
|
r85 | throw new ObjectDisposedException(ToString()); | ||
cin
|
r82 | |||
T instance; | ||||
if (m_queue.TryDequeue(out instance)) { | ||||
Interlocked.Decrement(ref m_count); | ||||
} else { | ||||
cin
|
r85 | instance = CreateInstance(); | ||
Debug.Assert(!Object.Equals(instance, default(T)) || _isValueType); | ||||
cin
|
r82 | } | ||
cin
|
r83 | return instance; | ||
cin
|
r82 | } | ||
cin
|
r85 | protected abstract T CreateInstance(); | ||
protected virtual void CleanupInstance(T instance) { | ||||
} | ||||
cin
|
r82 | public void Release(T instance) { | ||
cin
|
r85 | if ( Object.Equals(instance,default(T)) && !_isValueType) | ||
return; | ||||
cin
|
r83 | Thread.MemoryBarrier(); | ||
cin
|
r82 | if (m_count < m_size && !m_disposed) { | ||
Interlocked.Increment(ref m_count); | ||||
cin
|
r85 | CleanupInstance(instance); | ||
cin
|
r82 | |||
m_queue.Enqueue(instance); | ||||
// пока элемент возвращался в кеш, была начата операция освобождения всего кеша | ||||
// и возможно уже законцена, в таком случае следует извлечь элемент обратно и | ||||
// освободить его. Если операция освобождения кеша еще не заврешилась, то будет | ||||
// изъят и освобожден произвольный элемен, что не повлияет на ход всего процесса. | ||||
cin
|
r83 | if (m_disposed && m_queue.TryDequeue(out instance) && instance is IDisposable) | ||
((IDisposable)instance).Dispose() ; | ||||
cin
|
r82 | |||
} else { | ||||
cin
|
r83 | if (instance is IDisposable) | ||
((IDisposable)instance).Dispose(); | ||||
cin
|
r82 | } | ||
} | ||||
protected virtual void Dispose(bool disposing) { | ||||
if (disposing) { | ||||
m_disposed = true; | ||||
T instance; | ||||
while (m_queue.TryDequeue(out instance)) | ||||
cin
|
r83 | if (instance is IDisposable) | ||
((IDisposable)instance).Dispose(); | ||||
cin
|
r82 | } | ||
} | ||||
#region IDisposable implementation | ||||
public void Dispose() { | ||||
Dispose(true); | ||||
GC.SuppressFinalize(this); | ||||
} | ||||
#endregion | ||||
} | ||||
} | ||||