Background
SemaphoreSlim Class
Represents a lightweight alternative to Semaphore that limits the
number of threads that can access a resource or pool of resources
concurrently.
...
The count is decremented each time a thread enters the semaphore, and
incremented each time a thread releases the semaphore. To enter the
semaphore, a thread calls one of the Wait or WaitAsync overloads. To
release the semaphore, it calls one of the Release overloads. When the
count reaches zero, subsequent calls to one of the Wait methods block
until other threads release the semaphore. If multiple threads are
blocked, there is no guaranteed order, such as FIFO or LIFO, that
controls when threads enter the semaphore.
SemaphoreSlim.CurrentCount
Gets the number of remaining threads that can enter the SemaphoreSlim
object.
...
The initial value of the CurrentCount property is set by the call to
the SemaphoreSlim class constructor. It is decremented by each call to
the Wait or WaitAsync method, and incremented by each call to the
Release method.
That's to say, every time you enter a semaphore you reduce the remaining threads that can enter. If you have entered successfully, the count is decremented.
Calling the CancellationToken that is being awaited only has an effect on threads awaiting the WaitAsync
, or if you try to await the token again.
To answer the question, the CancellationToken is solely for the awaiting WaitAsync
, it has no affect on how many threads can enter the SemaphoreSlim
.
Furthermore
I think the real and pertinent question is, do you need to release a SemephoreSlim
that has been cancelled! and the answer is no. An awaiting SemephoreSlim
has not successfully entered or affected the count anyway, it's awaiting because there are no threads permissible.
And lastly, do you need release a SemephoreSlim
that has been timed out via the timeout overload. The answer to that is, this method returns a bool
as to whether it was entered successfully, that return value needs to be checked to determined whether it may need to be released.
Fun fact
This is the exact reason why you don't put the wait inside a try finally pattern that releases the slim.
// this can throw, or timeout
var result = await semaphore.WaitAsync(someTimeOut, tokenSource.Token);
if(!result)
return;
try
{
// synchronized work here
}
finally
{
semaphore.Release();
}
Releasing inappropriately will cause all sorts of problems and result in another exception sooner or later because you are exceeding the maximum count.