| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- using ARMeilleure.Translation.PTC;
- using System;
- using System.Collections.Concurrent;
- using System.Collections.Generic;
- namespace ARMeilleure.Common
- {
- class ThreadStaticPool<T> where T : class, new()
- {
- [ThreadStatic]
- private static ThreadStaticPool<T> _instance;
- public static ThreadStaticPool<T> Instance
- {
- get
- {
- if (_instance == null)
- {
- PreparePool(); // So that we can still use a pool when blindly initializing one.
- }
- return _instance;
- }
- }
- private static readonly ConcurrentDictionary<int, Stack<ThreadStaticPool<T>>> _pools = new();
- private static Stack<ThreadStaticPool<T>> GetPools(int groupId)
- {
- return _pools.GetOrAdd(groupId, (groupId) => new());
- }
- public static void PreparePool(
- int groupId = 0,
- ChunkSizeLimit chunkSizeLimit = ChunkSizeLimit.Large,
- PoolSizeIncrement poolSizeIncrement = PoolSizeIncrement.Default)
- {
- if (Ptc.State == PtcState.Disabled)
- {
- PreparePoolDefault(groupId, (int)chunkSizeLimit, (int)poolSizeIncrement);
- }
- else
- {
- PreparePoolSlim((int)chunkSizeLimit, (int)poolSizeIncrement);
- }
- }
- private static void PreparePoolDefault(int groupId, int chunkSizeLimit, int poolSizeIncrement)
- {
- // Prepare the pool for this thread, ideally using an existing one from the specified group.
- if (_instance == null)
- {
- var pools = GetPools(groupId);
- lock (pools)
- {
- _instance = (pools.Count != 0) ? pools.Pop() : new(chunkSizeLimit, poolSizeIncrement);
- }
- }
- }
- private static void PreparePoolSlim(int chunkSizeLimit, int poolSizeIncrement)
- {
- // Prepare the pool for this thread.
- if (_instance == null)
- {
- _instance = new(chunkSizeLimit, poolSizeIncrement);
- }
- }
- public static void ResetPool(int groupId = 0)
- {
- if (Ptc.State == PtcState.Disabled)
- {
- ResetPoolDefault(groupId);
- }
- else
- {
- ResetPoolSlim();
- }
- }
- private static void ResetPoolDefault(int groupId)
- {
- // Reset, limit if necessary, and return the pool for this thread to the specified group.
- if (_instance != null)
- {
- var pools = GetPools(groupId);
- lock (pools)
- {
- _instance.Clear();
- _instance.ChunkSizeLimiter();
- pools.Push(_instance);
- _instance = null;
- }
- }
- }
- private static void ResetPoolSlim()
- {
- // Reset, limit if necessary, the pool for this thread.
- if (_instance != null)
- {
- _instance.Clear();
- _instance.ChunkSizeLimiter();
- }
- }
- public static void DisposePools()
- {
- if (Ptc.State == PtcState.Disabled)
- {
- DisposePoolsDefault();
- }
- else
- {
- DisposePoolSlim();
- }
- }
- private static void DisposePoolsDefault()
- {
- // Resets any static references to the pools used by threads for each group, allowing them to be garbage collected.
- foreach (var pools in _pools.Values)
- {
- foreach (var instance in pools)
- {
- instance.Dispose();
- }
- pools.Clear();
- }
- _pools.Clear();
- }
- private static void DisposePoolSlim()
- {
- // Dispose the pool for this thread.
- if (_instance != null)
- {
- _instance.Dispose();
- _instance = null;
- }
- }
- private List<T[]> _pool;
- private int _chunkIndex = -1;
- private int _poolIndex = -1;
- private int _chunkSizeLimit;
- private int _poolSizeIncrement;
- private ThreadStaticPool(int chunkSizeLimit, int poolSizeIncrement)
- {
- _chunkSizeLimit = chunkSizeLimit;
- _poolSizeIncrement = poolSizeIncrement;
- _pool = new(chunkSizeLimit * 2);
- AddChunkIfNeeded();
- }
- public T Allocate()
- {
- if (++_poolIndex >= _poolSizeIncrement)
- {
- AddChunkIfNeeded();
- _poolIndex = 0;
- }
- return _pool[_chunkIndex][_poolIndex];
- }
- private void AddChunkIfNeeded()
- {
- if (++_chunkIndex >= _pool.Count)
- {
- T[] pool = new T[_poolSizeIncrement];
- for (int i = 0; i < _poolSizeIncrement; i++)
- {
- pool[i] = new T();
- }
- _pool.Add(pool);
- }
- }
- public void Clear()
- {
- _chunkIndex = 0;
- _poolIndex = -1;
- }
- private void ChunkSizeLimiter()
- {
- if (_pool.Count >= _chunkSizeLimit)
- {
- int newChunkSize = _chunkSizeLimit / 2;
- _pool.RemoveRange(newChunkSize, _pool.Count - newChunkSize);
- _pool.Capacity = _chunkSizeLimit * 2;
- }
- }
- private void Dispose()
- {
- _pool = null;
- }
- }
- }
|