Before I spend too long reinventing the wheel, I wanted to check in case there is already a class in .Net that does what I want.
What I want is something a bit like a Semaphore (or perhaps even like a CountdownEvent), but slightly different.
I have a requirement where I have a varying number of "resources" available, and I want a thread to wait efficiently when there are zero resources available. In the meantime, another thread can free up a resource, which should immediately release the other waiting thread.
This sounds a lot like a Semaphore, but its not because a Semaphore (as far as I can see) treats each thread as a "resource" in terms of counting them.
Anyway, here's my first simple implementation of what I want. It has no disposal, code contracts, error handling, timeout support or cancellation support yet, but it should demonstrate what I want:
public sealed class ResourceCounter
{
/// <summary>Create with the specified number of resources initially available.</summary>
public ResourceCounter(int resourceCount)
{
_resourceCount = resourceCount;
if (_resourceCount > 0)
{
_resourceAvailable.Set();
}
}
/// <summary>Acquires a resource. Waits forever if necessary.</summary>
public void Acquire()
{
while (true)
{
_resourceAvailable.Wait();
lock (_lock)
{
if (_resourceCount > 0)
{
if (--_resourceCount == 0)
{
_resourceAvailable.Reset();
}
return;
}
}
}
}
/// <summary>Releases a resource.</summary>
public void Release()
{
lock (_lock)
{
++_resourceCount;
_resourceAvailable.Set();
}
}
private int _resourceCount;
private readonly object _lock = new object();
private readonly ManualResetEventSlim _resourceAvailable = new ManualResetEventSlim();
}
The usage pattern is very simple:
Construct a ResourceCounter with the required initial resource count (which can be zero or more).
A thread which wants to acquire a resource calls ResourceCounter.Acquire(), which will not return until a resource is available and has been acquired.
A thread which wants to release a resource calls ResourceCounter.Release(), which will release a resource and return immediately.
Note that any thread can release a resource; it doesn't have to be the one that acquired the resource.
I'm using this as part of some multithreaded pipeline code where one thread is responsible for enqueuing work items, several threads are processing the work items, and another thread is outputting the processed work items. The thread which outputs the processed work items has to multiplex them (since the processing threads may output completed items in any order), and I needed a mechanism to stop work items from being queued endlessly while the multiplexer waits for a tardy item.
(See Pipelines, multiplexing, and unbounded buffering for some background on this.)
Anyway, is there anything already available to do this, or should I continue to develop my own class for it?
[EDIT]
As noted below, a SemaphoreSlim does exactly the right thing. I'd rejected it because I thought that the thread that called Wait() had to be the one that called Release(), but that wasn't the case. This is what I get for coding on a Sunday... ;)