SemaphoreSlim的Wait(Int32)方法在传递零时立即返回吗?

Ros*_*oss 6 c# concurrency semaphore .net-4.0

在Semaphore的WaitOne(Int32)方法的MSDN文档中,它表示给它一个值为零将导致该方法立即返回而不等待一个槽打开.SemaphoreSlim版本的文档没有说同样的事情.SemaphoreSlim会分享这种行为吗?

我不确定如何保证自己测试的时机.

And*_*own 8

如果超时为0,则SemaphoreSlim.Wait总是会在返回之前尝试获取一个插槽,它不会等待一个时间长于几个操作和一个SpinOnce.

编辑:澄清:这可能是同样明显的行为Semaphore.从以下文档Semaphore:

它测试等待句柄的状态并立即返回

但是SemaphoreSlim,一旦你在Wait方法中,通过使用,确实可以让插槽有机会打开SpinOnce.

(结束编辑)

此外,SemaphoreSlim在尝试获取插槽之前运行一些操作.其中一个是a Monitor.Enter,所以它可以等待那个正在等待或释放的其他线程.因此,它不一定会立即返回.

据我所知,事件的顺序是:

  1. 创建一个 CancellationTokenRegistration
  2. 如果可用的插槽数是0,那么SpinWait.SpinOnce(或者跳过这个,如果NextSpinWillYieldtrue)(编辑:我粗略地强调步骤2执行与步骤5相同的测试,使其有机会旋转并且在插入之前有一个插槽可用最终测试和退出)
  3. 调用Monitor.Enter进入锁定(与Release和WaitAsync进入的锁相同)
  4. 将内部waitCount增加1
  5. 如果可用的插槽计数为0,则将waitCount减1并退出锁定,然后返回false
  6. 如果我们到达这里并且有一个免费插槽:
    • 将可用的插槽数减1(暗示:获取插槽)
    • AvailableWaitHandle如果正在使用waitHandle ,则重置waitHandle ,并且可用的插槽数现在再次为0
    • 将waitCount减1
    • 退出锁
    • 处置 CancellationTokenRegistration
    • 返回 true

(注意,使用非零超时的其他线程会间歇性地释放并获取用于通过调用来保护计数器的锁Monitor.Wait,因此您不会永远等待超时0,只是在很短的时间内.)

因此SemaphoreSlim,似乎不会分享完全相同的0超时行为Sempahore,因为它确实给插槽一个机会打开.(也许这就是为什么有- Semaphore.WaitOne并且SemaphoreSlim.Wait- 通过改变信号量的实例化来升级旧代码时导致代码不能编译,因此让我们检查行为).

文章Semaphore vs. SemaphoreSlim没有强调这种行为,只是两者之间的根本区别.

边注:

有趣的是,该参考文献也指出

[SemaphoreSlim]并没有支持...同步使用等待句柄的

然而,SemaphoreSlim.AvailableWaitHandle的文档却有所不同.