C# LIFOPool 对象池
代码
public
class
LIFOPool
<
T
>
: IPool
<
T
>
, IFreeness
where
T :
class
{
#region NestedTypes
internal struct LIFOEntry
{
public bool Idle;
public DateTime LastUpdate;
public T Value;
}
#endregion
#region StaticMembers
public const int DefaultMaxSize = 100 ;
public const int DefaultMinSize = 2 ;
public static readonly bool IsSubOfIDisposable;
static LIFOPool()
{
IsSubOfIDisposable = typeof (T).IsSubclassOf( typeof (IDisposable));
}
#endregion
#region Fields
private WeakEvent < EventHandler > eventFull;
private LookupItem < T > lookupItem;
private ReleaseItem < T > releaseItem;
private double lifeTime;
private int minSize, maxSize, offset, freeTimeout;
private GCHandle[] weakHandle;
private LIFOEntry[] container;
private ReaderWriterLockSlim locker;
#endregion
#region Properties
public event EventHandler Full
{
add
{
if (eventFull == null )
{
Interlocked.CompareExchange < WeakEvent < EventHandler >> ( ref eventFull, new WeakEvent < EventHandler > (), null );
}
eventFull.Add(value);
}
remove
{
if (eventFull != null )
{
eventFull.Remove(value);
}
}
}
public double LifeTime
{
set { Interlocked.Exchange( ref lifeTime, value); }
get { return lifeTime; }
}
int IFreeness.Capacity
{
get { return maxSize; }
}
public int MinSize
{
get { return minSize; }
}
public int MaxSize
{
get { return maxSize; }
}
public int Size
{
get { return offset + 1 ; }
}
public bool IsFull
{
get { return offset + 1 == maxSize; }
}
public int FreeTimeout
{
set { Interlocked.Exchange( ref freeTimeout, value); }
get { return freeTimeout; }
}
#endregion
#region Constructor
public LIFOPool(LookupItem < T > createDelegate, ReleaseItem < T > releaseDelegate)
: this (DefaultMinSize, DefaultMaxSize, createDelegate, releaseDelegate)
{
}
public LIFOPool( int min, int max, LookupItem < T > lookupDelegate, ReleaseItem < T > releaseDelegate)
{
if (lookupDelegate ="color: #000000;">== null )
{
throw new ArgumentNullException( " Lookup delegate can't be null. " );
}
T t1 = lookupDelegate(), t2 = lookupDelegate();
if ( object .ReferenceEquals(t1, t2))
{
throw new ArgumentException( " Lookup delegate can't return the same reference object. " );
}
lookupItem = lookupDelegate;
releaseItem = releaseDelegate;
lifeTime = Freer.DefaultLifeTime / 2D;
minSize = min;
maxSize = max;
freeTimeout = 2000 ;
weakHandle = new GCHandle[maxSize / 10 ];
GCHandle emptyHandle = GCHandle.Alloc( null , GCHandleType.Weak);
for ( int i = 0 ; i < weakHandle.Length; i ++ )
{
weakHandle[i] = emptyHandle;
}
container = new LIFOEntry[maxSize];
container[ 0 ].Idle = container[ 1 ].Idle = true ;
container[ 0 ].LastUpdate = container[ 1 ].LastUpdate = DateTime.Now;
container[ 0 ].Value = t1;
container[ 1 ].Value = t2;
offset ++ ;
locker = new ReaderWriterLockSlim();
}
#endregion
#region Methods
public void Store(T item)
{
if (releaseItem != null )
{
releaseItem(item);
}
locker.EnterUpgradeableReadLock();
try
{
int index = - 1 ;
for ( int i = offset; i > 0 ; i -- )
{
if (container[i].Value.Equals(item))
{
locker.EnterWriteLock();
try
{
container[i].Idle = true ;
}
finally
{
locker.ExitWriteLock();
}
index = i;
break ;
}
}
if (index == - 1 )
{
locker.EnterWriteLock();
try
{
if (offset + 1 == maxSize && (eventFull == null || ! eventFull.Raise( this , EventArgs.Empty)))
{
throw new PoolFullException();
}
container[offset].Idle = true ;
container[offset].LastUpdate = DateTime.Now;
container[offset ++ ].Value = item;
}
finally
{
locker.ExitWriteLock();
}
}
}
finally
{
locker.ExitUpgradeableReadLock();
}
}
public T Retrieve()
{
T item = null ;
locker.EnterReadLock();
try
{
for ( int i = 0 ; i < weakHandle.Length; i ++ )
{
if (weakHandle[i].Target != null )
{
weakHandle[i].Target = null ;
item = (T)weakHandle[i].Target;
break ;
}
}
}
finally
{
locker.ExitReadLock();
}
if (item == null )
{
locker.EnterUpgradeableReadLock();
try
{
if (offset + 1 == maxSize && (eventFull == null || ! eventFull.Raise( this , EventArgs.Empty)))
{
throw new PoolFullException();
}
for ( int i = offset; i > 0 ; i -- )
{
if (container[i].Idle)
{
locker.EnterWriteLock();
try
{
container[i].Idle = false ;
container[i].LastUpdate = DateTime.Now;
}
finally
{
locker.ExitWriteLock();
}
item = container[i].Value;
break ;
}
}
if (item == null )
{
locker.EnterWriteLock();
try
{
container[offset].Idle = false ;
container[offset].LastUpdate = DateTime.Now;
item = container[offset ++ ].Value = lookupItem();
}
finally
{
locker.ExitWriteLock();
}
}
}
finally
{
locker.ExitUpgradeableReadLock();
}
}
return item;
}
public int Free()
{
int freed = 0 ;
if (lifeTime != Timeout.Infinite && offset > minSize - 1 )
{
List < T > list = null ;
if (locker.TryEnterWriteLock(freeTimeout))
{
try
{
LIFOEntry entry;
for ( int i = 0 ; i <= offset; i ++ )
{
entry = container[i];
if (entry.LastUpdate.AddSeconds(lifeTime).CompareTo(DateTime.Now) <= 0 )
{
if (IsSubOfIDisposable && entry.Idle)
{
if (list == null )
{
list = new List < T > ();
}
list.Add(container[i].Value);
}
int j = i;
while (j < offset)
{
entry = container[j];
int nextJ = ++ j;
container[j] = container[nextJ];
container[nextJ] = entry;
}
for (j = 0 ; j < weakHandle.Length; j ++ )
{
if (weakHandle[i].Target == null )
{
weakHandle[i].Target = container[offset].Value;
container[offset].Value = null ;
break ;
}
}
freed ++ ;
if (offset -- <= minSize)
{
break ;
}
}
}
}
finally
{
locker.ExitWriteLock();
}
}
if (list != null )
{
list.ForEach(item => ((IDisposable)item).Dispose());
}
}
return freed;
}
#endregion
}
{
#region NestedTypes
internal struct LIFOEntry
{
public bool Idle;
public DateTime LastUpdate;
public T Value;
}
#endregion
#region StaticMembers
public const int DefaultMaxSize = 100 ;
public const int DefaultMinSize = 2 ;
public static readonly bool IsSubOfIDisposable;
static LIFOPool()
{
IsSubOfIDisposable = typeof (T).IsSubclassOf( typeof (IDisposable));
}
#endregion
#region Fields
private WeakEvent < EventHandler > eventFull;
private LookupItem < T > lookupItem;
private ReleaseItem < T > releaseItem;
private double lifeTime;
private int minSize, maxSize, offset, freeTimeout;
private GCHandle[] weakHandle;
private LIFOEntry[] container;
private ReaderWriterLockSlim locker;
#endregion
#region Properties
public event EventHandler Full
{
add
{
if (eventFull == null )
{
Interlocked.CompareExchange < WeakEvent < EventHandler >> ( ref eventFull, new WeakEvent < EventHandler > (), null );
}
eventFull.Add(value);
}
remove
{
if (eventFull != null )
{
eventFull.Remove(value);
}
}
}
public double LifeTime
{
set { Interlocked.Exchange( ref lifeTime, value); }
get { return lifeTime; }
}
int IFreeness.Capacity
{
get { return maxSize; }
}
public int MinSize
{
get { return minSize; }
}
public int MaxSize
{
get { return maxSize; }
}
public int Size
{
get { return offset + 1 ; }
}
public bool IsFull
{
get { return offset + 1 == maxSize; }
}
public int FreeTimeout
{
set { Interlocked.Exchange( ref freeTimeout, value); }
get { return freeTimeout; }
}
#endregion
#region Constructor
public LIFOPool(LookupItem < T > createDelegate, ReleaseItem < T > releaseDelegate)
: this (DefaultMinSize, DefaultMaxSize, createDelegate, releaseDelegate)
{
}
public LIFOPool( int min, int max, LookupItem < T > lookupDelegate, ReleaseItem < T > releaseDelegate)
{
if (lookupDelegate ="color: #000000;">== null )
{
throw new ArgumentNullException( " Lookup delegate can't be null. " );
}
T t1 = lookupDelegate(), t2 = lookupDelegate();
if ( object .ReferenceEquals(t1, t2))
{
throw new ArgumentException( " Lookup delegate can't return the same reference object. " );
}
lookupItem = lookupDelegate;
releaseItem = releaseDelegate;
lifeTime = Freer.DefaultLifeTime / 2D;
minSize = min;
maxSize = max;
freeTimeout = 2000 ;
weakHandle = new GCHandle[maxSize / 10 ];
GCHandle emptyHandle = GCHandle.Alloc( null , GCHandleType.Weak);
for ( int i = 0 ; i < weakHandle.Length; i ++ )
{
weakHandle[i] = emptyHandle;
}
container = new LIFOEntry[maxSize];
container[ 0 ].Idle = container[ 1 ].Idle = true ;
container[ 0 ].LastUpdate = container[ 1 ].LastUpdate = DateTime.Now;
container[ 0 ].Value = t1;
container[ 1 ].Value = t2;
offset ++ ;
locker = new ReaderWriterLockSlim();
}
#endregion
#region Methods
public void Store(T item)
{
if (releaseItem != null )
{
releaseItem(item);
}
locker.EnterUpgradeableReadLock();
try
{
int index = - 1 ;
for ( int i = offset; i > 0 ; i -- )
{
if (container[i].Value.Equals(item))
{
locker.EnterWriteLock();
try
{
container[i].Idle = true ;
}
finally
{
locker.ExitWriteLock();
}
index = i;
break ;
}
}
if (index == - 1 )
{
locker.EnterWriteLock();
try
{
if (offset + 1 == maxSize && (eventFull == null || ! eventFull.Raise( this , EventArgs.Empty)))
{
throw new PoolFullException();
}
container[offset].Idle = true ;
container[offset].LastUpdate = DateTime.Now;
container[offset ++ ].Value = item;
}
finally
{
locker.ExitWriteLock();
}
}
}
finally
{
locker.ExitUpgradeableReadLock();
}
}
public T Retrieve()
{
T item = null ;
locker.EnterReadLock();
try
{
for ( int i = 0 ; i < weakHandle.Length; i ++ )
{
if (weakHandle[i].Target != null )
{
weakHandle[i].Target = null ;
item = (T)weakHandle[i].Target;
break ;
}
}
}
finally
{
locker.ExitReadLock();
}
if (item == null )
{
locker.EnterUpgradeableReadLock();
try
{
if (offset + 1 == maxSize && (eventFull == null || ! eventFull.Raise( this , EventArgs.Empty)))
{
throw new PoolFullException();
}
for ( int i = offset; i > 0 ; i -- )
{
if (container[i].Idle)
{
locker.EnterWriteLock();
try
{
container[i].Idle = false ;
container[i].LastUpdate = DateTime.Now;
}
finally
{
locker.ExitWriteLock();
}
item = container[i].Value;
break ;
}
}
if (item == null )
{
locker.EnterWriteLock();
try
{
container[offset].Idle = false ;
container[offset].LastUpdate = DateTime.Now;
item = container[offset ++ ].Value = lookupItem();
}
finally
{
locker.ExitWriteLock();
}
}
}
finally
{
locker.ExitUpgradeableReadLock();
}
}
return item;
}
public int Free()
{
int freed = 0 ;
if (lifeTime != Timeout.Infinite && offset > minSize - 1 )
{
List < T > list = null ;
if (locker.TryEnterWriteLock(freeTimeout))
{
try
{
LIFOEntry entry;
for ( int i = 0 ; i <= offset; i ++ )
{
entry = container[i];
if (entry.LastUpdate.AddSeconds(lifeTime).CompareTo(DateTime.Now) <= 0 )
{
if (IsSubOfIDisposable && entry.Idle)
{
if (list == null )
{
list = new List < T > ();
}
list.Add(container[i].Value);
}
int j = i;
while (j < offset)
{
entry = container[j];
int nextJ = ++ j;
container[j] = container[nextJ];
container[nextJ] = entry;
}
for (j = 0 ; j < weakHandle.Length; j ++ )
{
if (weakHandle[i].Target == null )
{
weakHandle[i].Target = container[offset].Value;
container[offset].Value = null ;
break ;
}
}
freed ++ ;
if (offset -- <= minSize)
{
break ;
}
}
}
}
finally
{
locker.ExitWriteLock();
}
}
if (list != null )
{
list.ForEach(item => ((IDisposable)item).Dispose());
}
}
return freed;
}
#endregion
}