using System.Threading.Tasks;
using System.Collections.Generic;
using System.Diagnostics;
public class ThreadSafeValuePool<T> {
private readonly object lockObj;
private readonly IList<T> internalList;
public ThreadSafeValuePool(params T[] values) : this(values.AsEnumerable<T>())
public ThreadSafeValuePool(IEnumerable<T> values){
internalList = new List<T>(values);
public T Borrow(CancellationToken token) {
while(!token.IsCancellationRequested)
if (Monitor.TryEnter(lockObj, TimeSpan.FromMilliseconds(1)))
if (internalList.Count() > 0)
var item = internalList[0];
internalList.RemoveAt(0);
token.WaitHandle.WaitOne(TimeSpan.FromMilliseconds(1));
public T Borrow(Func<T, bool> selectorFn, CancellationToken token)
while(!token.IsCancellationRequested)
if (Monitor.TryEnter(lockObj, TimeSpan.FromMilliseconds(1)))
T targetValue = internalList.FirstOrDefault(v => selectorFn(v));
internalList.Remove(targetValue);
token.WaitHandle.WaitOne(TimeSpan.FromMilliseconds(1));
public T Borrow(T specificValue, CancellationToken token) =>
Borrow((T item) => specificValue.Equals(item), token);
public void ReturnValue(T returnedValue, CancellationToken token)
while(!token.IsCancellationRequested)
if (Monitor.TryEnter(lockObj, TimeSpan.FromMilliseconds(1)))
internalList.Add(returnedValue);
token.WaitHandle.WaitOne(TimeSpan.FromMilliseconds(1));
public static void Main()
var threadSafePool = new ThreadSafeValuePool<string>("1", "2", "3", "4", "5");
for(int i = 0; i < 5; i++)
var borroweredValue = threadSafePool.Borrow(CancellationToken.None);
Console.WriteLine($"Value borrowered was {borroweredValue}");
CancellationTokenSource manualCancellationToken = new CancellationTokenSource();
manualCancellationToken.CancelAfter(100);
var sw = new Stopwatch();
threadSafePool.Borrow(manualCancellationToken.Token);
Console.WriteLine($"borrow blocked {sw.ElapsedMilliseconds}ms before cancellation");
threadSafePool.ReturnValue("5", CancellationToken.None);
string borrowedValue = threadSafePool.Borrow(CancellationToken.None);
Console.WriteLine($"Got a value of {borrowedValue} back after blocking for {sw.ElapsedMilliseconds}ms");
threadSafePool.ReturnValue("5", CancellationToken.None);
threadSafePool.ReturnValue("3", CancellationToken.None);
borrowedValue = threadSafePool.Borrow("3", CancellationToken.None);
Console.WriteLine($"Got the specified value of {borrowedValue} back after blocking for {sw.ElapsedMilliseconds}ms");