Pregunta ¿El método de espera de SemaphoreSlim (Int32) regresa inmediatamente cuando se pasa a cero?


En el Documentos de MSDN para el método WaitOne (Int32) de Semaphore, dice que al darle un valor de cero hará que el método regrese inmediatamente sin esperar a que se abra un espacio. La documentación para el SemaphoreSlim la versión no dice lo mismo. ¿SemaphoreSlim comparte este comportamiento?

No estoy seguro de cómo garantizar el momento de probar esto yo mismo.


6
2018-01-29 01:24


origen


Respuestas:


Si pasó un tiempo de espera de 0 entonces SemaphoreSlim.Wait siempre intentará adquirir una ranura antes de regresar, simplemente no esperará una durante más tiempo que unas pocas operaciones y una SpinOnce.

EDIT: aclaración: Este es probablemente el mismo comportamiento aparente que Semaphore. De la documentación para Semaphore:

Prueba el estado del identificador de espera y devuelve inmediatamente

sin embargo SemaphoreSlim le da a una ranura la oportunidad de abrirse una vez que esté en el método de Espera, mediante el uso de SpinOnce.

(fin de editar)

También, SemaphoreSlim ejecuta algunas operaciones antes de intentar adquirir una ranura. Uno de estos es un Monitor.Enter, por lo que podría esperar en otros subprocesos en ese punto que estén en el proceso de esperar o liberar. No necesariamente, por lo tanto, regresará inmediatamente.

Hasta donde sé, el orden de los eventos es:

  1. Crear un CancellationTokenRegistration
  2. Si el recuento de tragamonedas disponible es 0, entonces SpinWait.SpinOnce (o salta esto si NextSpinWillYield es true) (editar: Hice esto audaz para enfatizar que el paso 2 hace la misma prueba que el paso 5, dándole la oportunidad de girar y tener una ranura disponible antes de la prueba final y salir)
  3. Llamada Monitor.Enter para ingresar al bloqueo (el mismo bloqueo que liberan Release y WaitAsync)
  4. Incremente el waitCount interno en 1
  5. Si el recuento de tragamonedas disponible es 0, disminuya waitCount en 1 y salga del bloqueo, luego regreso false
  6. Si llegamos aquí y hay un tragamonedas gratis:
    • disminuir el recuento de tragamonedas disponible en 1 (implicación: adquirir el tragamonedas)
    • Restablecer el waitHandle debajo AvailableWaitHandle, si se está utilizando y el recuento de espacios disponibles ahora es 0 otra vez
    • Disminuir waitCount por 1
    • Salir de la cerradura
    • Eliminar el CancellationTokenRegistration
    • regreso true

(Tenga en cuenta que otros subprocesos que usan tiempos de espera distintos de cero lanzan intermitentemente y adquieren el bloqueo utilizado para proteger los contadores al llamar Monitor.Wait, por lo que no esperará por siempre con un tiempo de espera de 0, solo por muy poco tiempo).

Asi que SemaphoreSlim no parece compartir exactamente el mismo comportamiento de tiempo de espera 0 con Sempahore, ya que le da a un espacio la oportunidad de abrirse. (Tal vez es por eso que hay Semaphore.WaitOne y SemaphoreSlim.Wait - hacer que el código no se compile al actualizar el código antiguo simplemente cambiando la instanciación del semáforo, y por lo tanto haciendo que verifiquemos el comportamiento).

El artículo Semáforo vs. SemáforoSlim no resalta este comportamiento, solo las diferencias fundamentales entre los dos.

Nota al margen:

Curiosamente esa referencia también establece

[SemaphoreSlim] no no soporte ... el uso de un identificador de espera para la sincronización

Y sin embargo, la documentación para SemaphoreSlim.AvailableWaitHandle dice de manera diferente.


7
2018-05-07 12:35