public class ThreadContextPool<T> where T : class
{
#region NestedType
private struct Entry
{
public int ThreadID;
public T Value;
}
private struct PendingEntry
{
public int ThreadID;
public int ReturnCount;
}
private class GlobalPool
{
private int maxCount;
private Stack<T> items;
public int MaxCount
{
get { return maxCount; }
set
{
lock (items)
{
while (items.Count > value)
{
items.Pop();
}
maxCount = value;
}
}
}
public GlobalPool(int maxCount)
{
this.maxCount = maxCount;
this.items = new Stack<T>();
}
public void Clear()
{
lock (items)
{
items.Clear();
}
}
public void DecrementMaxCount()
{
lock (items)
{
if (items.Count == maxCount)
{
items.Pop();
}
maxCount--;
}
}
public bool Return(T value)
{
if (items.Count < MaxCount)
{
lock (items)
{
if (items.Count < MaxCount)
{
items.Push(value);
return true;
}
}
}
return false;
}
public T Take()
{
if (items.Count > 0)
{
lock (items)
{
if (items.Count > 0)
{
return items.Pop();
}
}
}
return null;
}
}
#endregion
#region Fields
private const int maxPendingEntries = 128;
private const int maxPromotionFailures = 64;
private const int maxReturnsBeforePromotion = 64;
private const int maxThreadItemsPerProcessor = 16;
private int maxCount, promotionFailures;
private Entry[] entries;
private PendingEntry[] pending;
private GlobalPool globalPool;
#endregion
#region Properties
public int MinSize
{
get { return 0; }
}
public int MaxSize
{
get { return maxCount; }
}
public int Size
{
get { throw new NotSupportedException(); }
}
#endregion
#region Methods
public ThreadContextPool(int maxCount)
{
int num = maxCount;
int num2 = maxThreadItemsPerProcessor + Environment.ProcessorCount;
if (num > num2)
{
num = num2;
}
this.maxCount = maxCount;
this.entries = new Entry[num];
this.pending = new PendingEntry[4];
this.globalPool = new GlobalPool(maxCount);
}
public void Clear()
{
for (int i = 0; i < entries.Length; i++)
{
entries[i].Value = null;
}
globalPool.Clear();
}
public bool Return(T item)
{
int managedThreadId = Thread.CurrentThread.ManagedThreadId;
if (managedThreadId == 0)
{
return false;
}
bool flag = ReturnToPerThreadPool(managedThreadId, item);
if (!flag)
{
RecordReturnToGlobalPool(managedThreadId);
flag = globalPool.Return(item);
}
return flag;
}
private bool ReturnToPerThreadPool(int thisThreadID, T value)
{
for (int i = 0; i < entries.Length; i++)
{
int threadID = entries[i].ThreadID;
if (threadID == thisThreadID)
{
if (entries[i].Value == null)
{
entries[i].Value = value;
return true;
}
return false;
}
if (threadID == 0)
{
break;
}
}
return false;
}
private void RecordReturnToGlobalPool(int thisThreadID)
{
for (int i = 0; i < pending.Length; i++)
{
int threadID = pending[i].ThreadID;
if (threadID == thisThreadID)
{
int num3 = pending[i].ReturnCount + 1;
if (num3 < maxReturnsBeforePromotion)
{
pending[i].ReturnCount = num3;
return;
}
pending[i].ReturnCount = 0;
if (!PromoteThread(thisThreadID))
{
HandlePromotionFailure(thisThreadID);
return;
}
break;
}
if (threadID == 0)
{
return;
}
}
}
private bool PromoteThread(int thisThreadID)
{
lock (entries)
{
for (int i = 0; i < entries.Length; i++)
{
int threadID = entries[i].ThreadID;
if (threadID == thisThreadID)
{
return true;
}
if (threadID == 0)
{
globalPool.DecrementMaxCount();
entries[i].ThreadID = thisThreadID;
return true;
}
}
}
return false;
}
private void HandlePromotionFailure(int thisThreadID)
{
int num = promotionFailures + 1;
if (num >= maxPromotionFailures)
{
lock (entries)
{
entries = new Entry[entries.Length];
globalPool.MaxCount = maxCount;
}
PromoteThread(thisThreadID);
}
else
{
promotionFailures = num;
}
}
public T Take()
{
int managedThreadId = Thread.CurrentThread.ManagedThreadId;
if (managedThreadId == 0)
{
return null;
}
T local = this.TakeFromPerThreadPool(managedThreadId);
if (local != null)
{
return local;
}
this.RecordTakeFromGlobalPool(managedThreadId);
return globalPool.Take();
}
private T TakeFromPerThreadPool(int thisThreadID)
{
for (int i = 0; i < entries.Length; i++)
{
int threadID = entries[i].ThreadID;
if (threadID == thisThreadID)
{
T local = entries[i].Value;
if (local != null)
{
entries[i].Value = null;
return local;
}
return null;
}
if (threadID == 0)
{
break;
}
}
return null;
}
private void RecordTakeFromGlobalPool(int thisThreadID)
{
for (int i = 0; i < pending.Length; i++)
{
int threadID = pending[i].ThreadID;
if (threadID == thisThreadID)
{
return;
}
if (threadID == 0)
{
lock (pending)
{
if (pending[i].ThreadID == 0)
{
pending[i].ThreadID = thisThreadID;
return;
}
}
}
}
if (pending.Length >= maxPendingEntries)
{
this.pending = new PendingEntry[pending.Length];
}
else
{
PendingEntry[] destinationArray = new PendingEntry[pending.Length * 2];
Array.Copy(pending, destinationArray, pending.Length);
this.pending = destinationArray;
}
}
#endregion
}