Reputation: 137
I have been trying to use a Semaphore to control number of requests that my service can handle. I.E.
class Service : IDisposable {
SemaphoreSlim s = new SemaphoreSlim(InitialCapacity);
....
async void ProcessRequest() {
await s.WaitAsync();
try {
......
} finally {
s.Release();
}
}
}
There are 2 problems I am encountering that I am not sure how to solve. I have been using similar hacks to resolve these problems, but I wonder if there is any better way
I want to be able to dynamically change the capacity of my service class, so I have something like this.
void ChangeCapacity(int newCapacity) {
int extraRequestsCount = newCapacity - oldCapacity;
if (extraRequestsCount > 0) {
s.Release(extraRequestsCount);
}
else if (extraRequestsCount < 0) {
for (int i = 0; i < -extraRequestsCount; i++) {
s.WaitAsync(); // try to steal some resources, over time...
}
}
}
At the dispose method, I want to make sure all the request processing completes before I dispose the semaphore, otherwise the s.Release() call in my ProcessRequest() would throw ObjectDisposedException so I did the following
public void Dispose() {
if (s!= null) {
for (int i = 0; i < oldCapacity; i++) {
s.Wait();
}
s.Dispose();
}
}
Note that I have been using loop to manually wait many times. This is really slow if the capacity is large. Is there a better way to do this? There's a Release(int count) for semaphore why isn't there a Wait(int count)?
Upvotes: 0
Views: 1222
Reputation: 34852
What I'd probably do is when the adjustment is made, replace your semaphore instance with a new semaphore with the desired capacity, and assign all future work to that semaphore. The existing and now dereferenced semaphore will not be garbage collected until all threads are done referencing it, so it should be safe to do this as long as you assign the semaphore variable locally to each thread.
Upvotes: 0