Semáforo: ¿para qué sirve el recuento inicial?

91

http://msdn.microsoft.com/en-us/library/system.threading.semaphoreslim.aspx

Para crear un semáforo, necesito proporcionar un recuento inicial y un recuento máximo. MSDN indica que un recuento inicial es:

El número inicial de solicitudes para el semáforo que se pueden otorgar al mismo tiempo.

Si bien establece que el recuento máximo es

El número máximo de solicitudes para el semáforo que se pueden otorgar al mismo tiempo.

Puedo entender que el recuento máximo es el número máximo de subprocesos que pueden acceder a un recurso al mismo tiempo. Pero, ¿de qué sirve el recuento inicial?

Si creo un semáforo con un recuento inicial de 0 y un recuento máximo de 2, ninguno de mis subprocesos podrá acceder al recurso. Si configuro el recuento inicial como 1 y el recuento máximo como 2, solo el subproceso del grupo de subprocesos puede acceder al recurso. Solo cuando configuro el recuento inicial y el recuento máximo como 2, 2 subprocesos pueden acceder al recurso al mismo tiempo. Entonces, ¿estoy realmente confundido acerca del significado del recuento inicial?

SemaphoreSlim semaphoreSlim = new SemaphoreSlim(0, 2); //all threadpool threads wait
SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 2);//only one thread has access to the resource at a time
SemaphoreSlim semaphoreSlim = new SemaphoreSlim(2, 2);//two threadpool threads can access the resource concurrently
Salvadera
fuente
7
¿Cómo es que nunca aceptó la respuesta de SVGreg?
Juan

Respuestas:

79

Sí, cuando el número inicial se establece en 0, todos los subprocesos estarán esperando mientras incrementa la propiedad "CurrentCount". Puede hacerlo con Release () o Release (Int32).

Release (...) - incrementará el contador de semáforos

Espera (...) - lo disminuirá

No puede incrementar el contador (propiedad "CurrentCount") más que el conteo máximo que estableció en la inicialización.

Por ejemplo:

SemaphoreSlim^ s = gcnew SemaphoreSlim(0,2); //s->CurrentCount = 0
s->Release(2); //s->CurrentCount = 2
...

s->Wait(); //Ok. s->CurrentCount = 1
...

s->Wait(); //Ok. s->CurrentCount = 0
...

s->Wait(); //Will be blocked until any of the threads calls Release()
SVGreg
fuente
1
Su código se presentará mejor en la respuesta que como un comentario.
ChrisF
14
LOL, probablemente sea la quinta vez que llego a esta misma respuesta porque la documentación del constructor siempre me confunde sobre qué valores establecer. Saludos
BlueStrat
70

Entonces, ¿estoy realmente confundido acerca del significado del recuento inicial?

Un punto importante que puede ayudar aquí es que Waitdisminuye el recuento de semáforos y lo Releaseincrementa.

initialCountes el número de accesos a recursos que se permitirán inmediatamente. O, en otras palabras, es el número de veces que Waitse puede llamar sin bloquear inmediatamente después de crear una instancia del semáforo.

maximumCountes el recuento más alto que puede obtener el semáforo. Es el número de veces que Releasese puede llamar sin lanzar una excepción asumiendo que el initialCountrecuento es cero. Si initialCountse establece en el mismo valor que maximumCountentonces, llamar Releaseinmediatamente después de que se creó una instancia del semáforo arrojará una excepción.

Brian Gideon
fuente
20
¡Esto es muy útil! Había estado pensando en Semaphores al revés, como en initialCount siendo el número de recursos BLOQUEADOS iniciales, no el número de recursos que están disponibles inmediatamente. Gracias.
Philip Tenn
5
@PhilipTenn, estoy de acuerdo - la documentación no es clara a este respecto
BlueStrat
Acepté
@Sandbox debería aceptar esta respuesta en mi opinión, ya que realmente explica el significado de initialCountparámetro.
Michał Turczyn
8

¿A cuántos subprocesos desea poder acceder a los recursos a la vez? Establezca su conteo inicial en ese número. Si ese número nunca va a aumentar durante la vida del programa, establezca su conteo máximo en ese número también. De esa manera, si tiene un error de programación en la forma en que libera el recurso, su programa se bloqueará y se lo informará.

(Hay dos constructores: uno que toma solo un valor inicial y otro que adicionalmente toma el recuento máximo. Use el que sea apropiado).

Karmastan
fuente
1

De esta manera, cuando el hilo actual crea el semáforo, podría reclamar algunos recursos desde el principio.

Erno
fuente
Entonces, ¿quiere decir que cuando quiero que dos subprocesos de trabajo accedan al recurso, debería cambiar el recuento inicial?
Sandbox
No. Es el hilo actual el que reclama un recuento. Si no desea que el hilo actual reclame ningún acceso pase 0 o use la sobrecarga con un parámetro.
Erno
1

Si desea que ningún hilo acceda a su recurso durante algún tiempo, pasa el recuento inicial como 0 y cuando desee otorgar acceso a todos ellos justo después de crear el semáforo, pasa el valor del recuento inicial igual al recuento máximo . Por ejemplo:

hSemaphore = CreateSemaphoreA(NULL, 0, MAX_COUNT, NULL) ;

//Do something here
//No threads can access your resource

ReleaseSemaphore(hSemaphore, MAX_COUNT, 0) ;

//All threads can access the resource now

Como se cita en la documentación de MSDN: "Otro uso de ReleaseSemaphore es durante la inicialización de una aplicación. La aplicación puede crear un semáforo con una cuenta inicial de cero. Esto establece el estado del semáforo en no señalizado y bloquea todos los subprocesos para que no accedan al recurso protegido. Cuando la aplicación termina su inicialización, utiliza ReleaseSemaphore para aumentar el recuento a su valor máximo, para permitir el acceso normal al recurso protegido ".

Abhineet
fuente
Lo siento, te di el ejemplo en C ++ aunque puedo despejar la duda.
Abhineet
0

Los semáforos se pueden utilizar para proteger un conjunto de recursos . Usamos grupos de recursos para reutilizar elementos que son costosos de crear , como conexiones de bases de datos.

Por tanto, el recuento inicial se refiere al número de recursos disponibles en el grupo al inicio de algún proceso. Cuando lea el initialCountcódigo en, debería pensar en términos de cuánto esfuerzo inicial está poniendo en la creación de este grupo de recursos.

¿Estoy realmente confundido acerca del significado del recuento inicial?

Initial count = Upfront cost

Como tal, dependiendo del perfil de uso de su aplicación, este valor puede tener un efecto dramático en el rendimiento de su aplicación. No es solo un número arbitrario.

Debe pensar detenidamente sobre lo que está creando, lo caro que es crearlos y cuántos necesita de inmediato. Literalmente, debería poder graficar el valor óptimo para este parámetro y probablemente debería pensar en hacerlo configurable para poder adaptar el rendimiento del proceso al momento en que se está ejecutando.

rismo
fuente
-1

Como lo explica MSDN en la sección Comentarios:

Si initialCount es menor que maximumCount, el efecto es el mismo que si el hilo actual hubiera llamado WaitOne (maximumCount menos initialCount) veces. Si no desea reservar ninguna entrada para el hilo que crea el semáforo, use el mismo número para maximumCount e initialCount.

Entonces, si el recuento inicial es 0 y el máximo es 2, es como si el hilo principal hubiera llamado a WaitOne dos veces, por lo que hemos alcanzado la capacidad (el recuento del semáforo es 0 ahora) y ningún hilo puede entrar en Semaphore. De manera similar, si el recuento inicial es 1 y el máximo es 2, WaitOnce se ha llamado una vez y solo puede ingresar un hilo antes de que alcancemos la capacidad nuevamente y así sucesivamente.

Si se usa 0 para el recuento inicial, siempre podemos llamar a Release (2) para aumentar el recuento de semáforos al máximo para permitir que el número máximo de subprocesos adquiera recursos.

Irfan
fuente