In the MSDN docs for Semaphore's WaitOne(Int32) method, it says that giving it a value of zero will cause the method to return immediately without waiting for a slot to open up. The documentation for the SemaphoreSlim version does not say the same thing. Does SemaphoreSlim share this behavior?
I'm not sure how to guarantee the timing to test this myself.
This defines the semaphore's count. 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.
The initial count of a semaphore is typically set to the maximum value. The count is then decremented from that level as the protected resource is consumed. Alternatively, you can create a semaphore with an initial count of zero to block access to the protected resource while the application is being initialized.
If passed a timeout of 0 then SemaphoreSlim.Wait
will always attempt to acquire a slot before returning, it just won't wait around for one for longer than a few operations and a SpinOnce
.
EDIT: clarification: This is probably the same apparent behaviour as Semaphore
. From the documentation for Semaphore
:
It tests the state of the wait handle and returns immediately
However SemaphoreSlim
does give a slot a chance of opening up once you are in the Wait method, through the use of SpinOnce
.
(end edit)
Also, SemaphoreSlim
runs a few operations before attempting to acquire a slot. One of these is a Monitor.Enter
, so it could wait on other threads at that point who are in the process of waiting or releasing. It will not necessarily, therefore, return immediately.
As far as I know the order of events is:
CancellationTokenRegistration
SpinWait.SpinOnce
(or skip this if NextSpinWillYield
is true
)
(edit: I made this bold to emphasise that step 2 does the same test as step 5, giving it a chance to spin and have a slot become available before the final test and exit)Monitor.Enter
to enter the lock (the same lock that Release and WaitAsync enters)false
AvailableWaitHandle
, if it is being used and the available slot count is now 0 againCancellationTokenRegistration
true
(Note that other threads who are using non-zero timeouts intermittently release and acquire the lock used to protect the counters by calling Monitor.Wait
, so you won't wait forever with a timeout of 0, just for a very short time.)
So SemaphoreSlim
would not seem to share the exact same 0 timeout behaviour with Sempahore
, as it does give a slot a chance to open up. (Maybe this is why there is Semaphore.WaitOne
and SemaphoreSlim.Wait
- to cause code not to compile when upgrading old code by just changing the instantiation of the Semaphore, and therefore making us check the behaviour).
The article Semaphore vs. SemaphoreSlim doesn't highlight this behaviour, just the fundamental differences between the two.
Side note:
Interestingly that reference also states
[SemaphoreSlim] does not support ... the use of a wait handle for synchronization
And yet the documentation for SemaphoreSlim.AvailableWaitHandle says differently.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With