Skip to content

Instantly share code, notes, and snippets.

@JustinPealing
Created May 4, 2018 18:44
Show Gist options
  • Save JustinPealing/472389e2f0c7a5f9176bb1fae7d8e6fe to your computer and use it in GitHub Desktop.
Save JustinPealing/472389e2f0c7a5f9176bb1fae7d8e6fe to your computer and use it in GitHub Desktop.
Awaitable pool of objects of type T
public class ObjectPool<T>
{
private readonly Queue<T> _items = new Queue<T>();
private readonly Queue<TaskCompletionSource<T>> _waits = new Queue<TaskCompletionSource<T>>();
public void Add(T value)
{
lock (_waits)
{
if (_waits.TryDequeue(out var wait))
wait.SetResult(value);
else
_items.Enqueue(value);
}
}
public Task<T> TakeAsync()
{
lock (_waits)
{
if (_items.TryDequeue(out var result))
return Task.FromResult(result);
else
{
var tcs = new TaskCompletionSource<T>();
_waits.Enqueue(tcs);
return tcs.Task;
}
}
}
}
[TestClass]
public class ObjectPoolTest
{
private readonly ObjectPool<string> _pool = new ObjectPool<string>();
/// <summary>
/// ObjectPool is a pool of object of type T. Add is used to add an item to the pool, and TakeAsync is
/// used to get an item from the pool.
/// </summary>
[TestMethod]
public async Task Take()
{
_pool.Add("test");
Assert.AreEqual("test", await _pool.TakeAsync());
}
/// <summary>
/// TakeAsync will wait until an object is added if there are no objects available in the pool.
/// </summary>
[TestMethod]
public void WaitForObject()
{
var task = _pool.TakeAsync();
Assert.IsFalse(task.IsCompleted);
_pool.Add("test");
Assert.IsTrue(task.IsCompleted);
Assert.IsFalse(_pool.TakeAsync().IsCompleted);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment