Imagine several tasks trying to use a pool of resources concurrently. A single resource from the pool can only be used by an specific number of tasks at time; the number can be one.
In a synchronous environment, it seems to me that WaitHandle.WaitAny
& Semaphore
is the way to go.
var resources = new[] { new Resource(...), new Resource(...) }; // 'Resource' custom class wrapers the resource
var semaphores = new[] { new Semaphore(1, 1), new Semaphore(1, 1) };
...
var index = WaitHandle.WaitAny(semaphores);
try
{
UseResource(resources[index]);
}
finally
{
semaphores[index].Release();
}
But what should we do in an asynchronous environment?
I generally recommend that developers separate the "pooling" logic from the "using" logic. One nice side benefit of that separation is that only the pooling logic requires synchronization.
So, you have a finite set of resources, and each resource can only be used by one thread at a time.
Since you can't create new resources on-demand, you'll need a signal to know when one is available. You can do this yourself, or you can use something like a
BufferBlock<T>
to act as an async-ready queue.Since each resource can only be used by one thread at a time, I recommend using the common
IDisposable
technique for freeing the resource back to the pool.Putting these together:
Usage:
or:
Any concerns remaining? Leave a comment.
I'd probably go with a mutex or a lock on an object. Either can force the thread to wait until the lock or mutex is released.
Following the asynchronous version
Task.WhenAny
&SemaphoreSlim
.