7

在 Semaphore 的 WaitOne(Int32) 方法的MSDN 文档中,它说给它一个零值将导致该方法立即返回,而无需等待插槽打开。SemaphoreSlim版本的文档并没有说同样的话。SemaphoreSlim 是否有这种行为?

我不确定如何保证自己测试的时间。

4

1 回答 1

10

如果通过了 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(含义:获取槽)
    • 重置下的waitHandle AvailableWaitHandle,如果它正在被使用并且可用插槽计数现在再次为0
    • 将 waitCount 减 1
    • 退出锁
    • 处置CancellationTokenRegistration
    • 返回true

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

所以SemaphoreSlim似乎不会与 0 共享完全相同的超时行为Sempahore,因为它确实给了一个插槽打开的机会。(也许这就是为什么存在Semaphore.WaitOneSemaphoreSlim.Wait- 仅通过更改信号量的实例化来导致代码在升级旧代码时无法编译,因此让我们检查行为)。

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

边注:

有趣的是,该参考资料还指出

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

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

于 2013-05-07T12:35:14.503 回答