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

时间:2013-01-29 01:24:34

标签: c# .net-4.0 concurrency semaphore

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

我不知道如何保证自己测试的时机。

1 个答案:

答案 0 :(得分:8)

如果超时为0,则SemaphoreSlim.Wait将始终尝试在返回之前获取一个插槽,它不会等待一个时间超过几个操作并且SpinOnce

编辑:澄清:这可能与Semaphore的行为相同。来自Semaphore的文档:

  

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

但是,SemaphoreSlim通过使用SpinOnce,确实为您提供了在Wait方法中打开的机会。

(结束编辑)

此外,SemaphoreSlim在尝试获取插槽之前会运行一些操作。其中一个是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,如果正在使用它,可用的插槽数现在再次为0
    • 将waitCount减少1
    • 退出锁定
    • 弃置CancellationTokenRegistration
    • 返回true
  7. (注意,使用非零超时的其他线程间歇性地释放并获取用于通过调用Monitor.Wait来保护计数器的锁,因此您不会永远等待超时为0,仅用于很短的时间。)

    所以SemaphoreSlim似乎与Sempahore无法共享完全相同的0超时行为,因为它确实为插槽提供了打开的机会。 (也许这就是Semaphore.WaitOneSemaphoreSlim.Wait的原因 - 只需更改信号量的实例化就可以在升级旧代码时导致代码无法编译,从而让我们检查行为。)

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

    旁注:

    有趣的是,该引用也说明了

      

    [SemaphoreSlim] 支持...使用等待句柄进行同步

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