2009-08-03 15 views
13

Il semaforo può essere inferiore a 0? Voglio dire, dire che ho un semaforo con N = 3 e chiamo "down" 4 volte, quindi N rimarrà 0 ma un processo verrà bloccato?Come funziona il semaforo?

E allo stesso modo, se all'inizio richiamo, N può essere superiore a 3? Perché come vedo io, se N può essere superiore a 3 se all'inizio richiama un paio di volte, poi più tardi potrei chiamare più volte di me, mettendo così più processi nella sezione critica, quindi il semaforo mi consente .

Se qualcuno lo chiarisse un po 'per me lo apprezzerò molto.

Greg

+0

Vedere anche http://stackoverflow.com/questions/184147/countdownlatch-vs-semaphore – finnw

risposta

6

chiamata verso il basso quando si tratta di 0 non dovrebbe funzionare. Chiamare quando è 3 funziona. (Sto pensando a Java).

Lasciatemi aggiungere altro. Molte persone pensano a serrature come i semafori (binari) (es. N = 1, quindi il valore del semaforo è 0 (tenuto) o 1 (non trattenuto)). Ma questo non è giusto. Una serratura ha una nozione di "proprietà", quindi potrebbe essere "rientrante". Ciò significa che un thread che contiene un lock, è autorizzato a chiamare lock() di nuovo (spostando efficacemente il conteggio da 0 a -1), perché il thread detiene già il lock e gli è consentito "reinserirlo". Le serrature possono anche essere non rientranti. Ci si aspetta che un portablocco chiami unlock() lo stesso numero di volte di lock().

I semafori non hanno alcuna idea di proprietà, quindi non possono essere rientranti, sebbene possano essere acquisiti quanti più permessi disponibili. Ciò significa che un thread deve bloccare quando incontra un valore pari a 0, finché qualcuno non incrementa il semaforo.

Inoltre, in quello che ho visto (che è Java), è possibile incrementare il semaforo maggiore di N, e anche questo ha a che fare con la proprietà: un semaforo non ha la nozione di proprietà in modo che qualcuno possa darlo di più permessi. A differenza di un thread, dove ogni volta che un thread chiama unlock() senza tenere un lock, si tratta di un errore. (In java genererà un'eccezione).

Spero che questo modo di pensarci sia d'aiuto.

16

(Usando la terminologia da java.util.concurrent.Semaphore dato il tag Java. Alcuni di questi dettagli sono specifico dell'implementazione. Ho il sospetto che il vostro "down" è il metodo del semaforo Java acquire(), e la vostra "up" è release().)

Sì, l'ultima chiamata a acquire() bloccherà fino a quando un altro thread chiama release() o tuo thread viene interrotto.

Sì, è possibile chiamare release() più volte, quindi giù più volte, almeno con java.util.concurrent.Semaphore.

Alcune altre implementazioni di un semaforo possono avere un'idea di un numero "massimo" di permessi e una chiamata al rilascio oltre tale limite fallirebbe. La classe Java Semaphore consente una situazione inversa, in cui un semaforo può iniziare con un numero negativo di autorizzazioni e tutte le chiamate acquire() avranno esito negativo fino a quando non ci saranno state abbastanza chiamate release(). Una volta che il numero di permessi è diventato non negativo, non diventerà mai più negativo.

+0

È sicuro dire che il semaforo negativo si comporta come una levetta per il conto alla rovescia? Effettivamente non posso fare nulla quando viene raggiunta l'ultima versione (Count = 0). O ci sono altri casi in cui vorrei utilizzare un semaforo negativo? – jtkSource

+0

@jtkSource: Non ne conosco uno a caso. –

1

Basta vedere N come contatore che conta la tua risorsa limitata. Dato che non puoi avere un numero negativo di risorse, N rimane> = 0. Se il numero delle risorse disponibili cambia, anche il massimo N deve essere cambiato. Non lo considererei un buon stile per incrementare n senza decrementarlo prima in nessun altro caso.

2

Sì, un valore negativo indica che sono presenti processi in attesa del rilascio del semaforo. Un valore positivo significa che è possibile chiamare acquisire più volte prima che i blocchi del semaforo.

Si potrebbe pensare al valore in questo modo: un numero positivo significa che ci sono molte risorse disponibili. Un valore negativo significa che ci sono molte entità che necessitano di una risorsa quando tutte le risorse sono prese al momento. Quando acquisisci una risorsa decrementi il ​​valore, quando lo rilasci aumenti il ​​valore. Se il valore è ancora> = 0 dopo il decremento ottieni la risorsa, altrimenti la tua entità viene messa in coda.

Una bella spiegazione di semafori in Wikipedia: http://en.wikipedia.org/wiki/Semaphore_(programming)

8

Hi Greg considerare seguente esempio:

void main (String [] args) public static getta 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()); 
} 

Se si vede l'uscita u otterrà seguente:

Acquire: 0 Rilasciato: 1 Rilasciato: 2 Rilasciato: 3 Rilasciato: 4 Acquire: 3 Acquire: 2 Acquire: 1 Acquire: 0 E aspettare sta succedendo.

Quindi, in pratica permesso aumenterà ad ogni rilascio e l'acquisizione diminuirà fino a 0. Una volta raggiunto 0 attenderà fino al rilascio è chiamato stesso oggetto :)

0

Utilizzando java.util.concurrent.Semaphore con metodi acquire() e release(), penso che i permessi saranno sempre> = 0. Diciamo che si desidera sincronizzare i thread in modo che solo 1 thread possa essere inserito all'interno del ciclo. Se sem è il tipo di semaforo con valore iniziale 1, questo non funzionerà per più di 2 thread.

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 } 

Tuttavia, è possibile implementare la classe Semaforo da Java e rendere il vostro propria classe che permette questo.

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++; 
    } 
} 

} 

Ora val può essere negativo. Tuttavia, non sono sicuro che questo sia completamente sicuro, perché se abbiamo il segnale da un thread e attendiamo dall'altro e provano val ++ e val-- questo può essere cattivo. (le possibilità per questo sono molto piccole ma esistono, quindi se stai codificando e devi essere al 100% nessun errore, non ti consiglio di usare questo codice) In conclusione questo è il motivo per cui è meglio usare il concetto di monitor in java e parole chiave sincronizzate.