2009-08-03 30 views
13

¿Puede el semáforo ser menor que 0? Quiero decir, decir que tengo un semáforo con N = 3 y llamo "abajo" 4 veces, entonces N seguirá siendo 0 pero se bloqueará un proceso.¿Cómo funciona el semáforo?

Y a la inversa, si al principio llamo, ¿puede N ser mayor que 3? Porque, como yo lo veo, si N puede ser mayor que 3 si al principio llamo un par de veces, luego podría llamar más veces de lo que puedo, poniendo así más procesos en la sección crítica, entonces el semáforo me permite .

Si alguien me aclara un poco, lo apreciaré mucho.

Greg

+0

Véase también http://stackoverflow.com/questions/184147/countdownlatch-vs-semaphore – finnw

Respuesta

6

Llamando abajo cuando es 0, no debería funcionar. Llamar cuando es 3 funciona. (Estoy pensando en Java).

Déjenme agregar un poco más. Mucha gente piensa en bloqueos como semáforos (binarios) (es decir, N = 1, por lo que el valor del semáforo es 0 (sostenido) o 1 (no retenido)). Pero esto no es del todo correcto. Una cerradura tiene una noción de "propiedad" por lo que puede ser "reentrada". Eso significa que un hilo que contiene un bloqueo, permite volver a llamar a lock() (moviendo efectivamente el conteo de 0 a -1), porque el hilo ya tiene el bloqueo y se le permite "reingresarlo". Los bloqueos también pueden ser no reentrantes. Se espera que un portador de cerradura llame al desbloqueo() la misma cantidad de veces que lock().

Los semáforos no tienen noción de propiedad, por lo que no pueden ser reentrantes, aunque se pueden adquirir tantos permisos como estén disponibles. Eso significa que un hilo debe bloquearse cuando encuentra un valor de 0, hasta que alguien incremente el semáforo.

Además, en lo que he visto (que es Java), puede incrementar el semáforo mayor que N, y eso también tiene que ver con la propiedad: un semáforo no tiene noción de propiedad así que cualquiera puede darle más permisos. A diferencia de un hilo, donde cada vez que un hilo llama a desbloquear() sin mantener un bloqueo, es un error. (En java arrojará una excepción).

Espero que esta forma de pensar en ello ayude.

16

(Utilizando la terminología de java.util.concurrent.Semaphore dada la etiqueta de Java. Algunos de estos detalles son específicos de la implementación. Sospecho que su "abajo" es el método del semáforo de Java acquire(), y su "arriba" es release().)

Sí, la última llamada a acquire() bloqueará hasta que otro subproceso llama release() o el hilo se interrumpe.

Sí, puede llamar al release() más veces, luego hacia abajo más veces - al menos con java.util.concurrent.Semaphore.

Algunas otras implementaciones de un semáforo pueden tener una idea de un número "máximo" de permisos, y fallaría una llamada a liberar más allá de ese máximo. La clase Java Semaphore permite una situación inversa, donde un semáforo puede comenzar con un número negativo de permisos, y todas las llamadas acquire() fallarán hasta que haya habido suficientes llamadas release(). Una vez que el número de permisos se ha convertido en no negativo, nunca volverá a ser negativo.

+0

¿Es seguro decir que el semáforo negativo actúa como un bloqueo de cuenta atrás? Efectivamente, no puedo hacer nada cuando se alcanza el último lanzamiento (Count = 0). ¿O hay algún otro uso en el que quisiera usar un semáforo negativo? – jtkSource

+0

@jtkSource: No sé de una sola vez. –

1

Simplemente vea N como el contador que cuenta su recurso limitado. Como no puede tener un número negativo de recursos, N permanece> = 0. Si cambia el número de recursos disponibles, también se debe cambiar la N máxima. No consideraría un buen estilo incrementar n sin disminuirlo primero en ningún otro caso.

2

Sí, un valor negativo significa que tiene procesos esperando que se libere el semáforo. Un valor positivo significa que puede llamar a adquirir eso muchas veces antes de que el semáforo se bloquee.

Podría pensar en el valor de esta manera: un número positivo significa que hay muchos recursos disponibles. Un valor negativo significa que hay muchas entidades que necesitan un recurso cuando se toman todos los recursos en este momento. Cuando adquiere un recurso, disminuye el valor, cuando lo libera aumenta el valor. Si el valor sigue siendo> = 0 después del decremento, obtienes el recurso; de lo contrario, tu entidad quedará en una cola.

Una buena explicación de semáforos en Wikipedia: http://en.wikipedia.org/wiki/Semaphore_(programming)

8

Hola Greg consideran siguiente ejemplo:

public void main (String [] args) estáticas lanza InterruptedException {

Semaphore available = new Semaphore(1, true); 

    available.acquire(); 
    System.out.println("Acquire : " +available.availablePermits()); 

    available.release(); 
    System.out.println("Released : " +available.availablePermits()); 

    available.release(); 
    System.out.println("Released : " +available.availablePermits()); 

    available.release(); 
    System.out.println("Released : " +available.availablePermits()); 

    available.release(); 
    System.out.println("Released : " +available.availablePermits()); 

    available.acquire(); 
    System.out.println("Acquire : " +available.availablePermits()); 

    available.acquire(); 
    System.out.println("Acquire : " +available.availablePermits()); 

    available.acquire(); 
    System.out.println("Acquire : " +available.availablePermits()); 

    available.acquire(); 
    System.out.println("Acquire : " +available.availablePermits()); 

    available.acquire(); 
    System.out.println("Acquire : " +available.availablePermits()); 
} 

Si ve la salida u conseguirá siguiente:

Adquirir: 0 Publicación: 1 Publicada: 2 Publicada: 3 Publicada: 4 Adquirir: 3 Adquirir: 2 Adquisición: 1 Adquirir: 0 Y espera que continúe.

Así que básicamente permiten aumentará en cada lanzamiento y adquirir disminuirá hasta 0. Una vez que se llega a 0 se va a esperar hasta el lanzamiento se llama el mismo objeto :)

0

Usando java.util.concurrent.Semaphore con métodos acquire() y release(), creo que los permisos siempre serán> = 0. Digamos que quieres sincronizar los hilos para que solo 1 hilo pueda estar dentro del ciclo. Si sem es el tipo de semáforo que tiene el valor inicial 1, esto no funcionará para más de 2 subprocesos.

while(true){    

    sem.wait(); // wait is acquire 

    for(int i=0; i<=5; i++){ 

     try { 
      Thread.sleep(250); 
     }catch (InterruptedException e) {} 

     System.out.println("Thread "+ threadname+ " " + i); 

      } 
    sem.signal(); // signal is release } 

Sin embargo, puede implementar la clase de semáforo de Java y crear su propia clase que lo permita.

package yourpackage; 

import java.util.concurrent.Semaphore; 

public class SemaphoreLayer { 
public Semaphore s=null; 
public String name; 
private int val; 

public SemaphoreLayer(int i){ 
    s=new Semaphore(i); val=i; 
} 

public void wait(){ 
try { 
    val--; 
    s.acquire(); 

    } catch (InterruptedException e) { 
    System.out.println("Error signal semaphorelayer"); 
}} 

public void signal(){ 
    if(val<0){val++;}{ 
     s.release(); 
     val++; 
    } 
} 

} 

Ahora val puede ser negativo. Sin embargo, no estoy seguro de que esto sea completamente seguro, porque si tenemos la señal de un hilo y esperamos del otro e intentamos val ++ y val-- esto puede ser malo. (Las posibilidades de que esto sea muy pequeño pero aún existen, así que si está codificando y tiene que estar al 100% sin errores, no recomiendo usar este código) En conclusión, esta es la razón por la que es mejor utilizar el concepto de monitores en java y palabra clave sincronizada.