2009-08-03 13 views
13

Czy semafor może być mniejszy od 0? Mam na myśli, powiedzmy, że mam semafor z N = 3 i dzwonię "w dół" 4 razy, a N pozostanie 0, ale jeden proces zostanie zablokowany?Jak działa semafor?

I tak samo, jeśli na początku dzwonię, czy N może być wyższa niż 3? Ponieważ, jak widzę, jeśli N może być wyższy niż 3, jeśli na początku wywołuję kilka razy, to później mógłbym wywołać więcej razy niż ja, w ten sposób umieszczając więcej procesów w sekcji krytycznej, a następnie semafor pozwala mi .

Jeśli ktoś by mi to wyjaśnił, z pewnością to doceniam.

Greg

+0

Zobacz także http://stackoverflow.com/questions/184147/countdownlatch-vs-semaphore – finnw

Odpowiedz

6

Wywołanie w dół, gdy jest 0 nie powinna działać. Wywołanie, gdy jest 3, działa. (Myślę o Javie).

Pozwolę sobie dodać trochę więcej. Wiele osób myśli o blokadach takich jak semafory (binarne) (np. - N = 1, więc wartość semafora wynosi 0 (wstrzymane) lub 1 (nie trzymane)). Ale to nie jest w porządku. Blokada ma pojęcie "własności", więc może to być "reentrant". Oznacza to, że wątek, który trzyma blokadę, może ponownie wywołać funkcję lock() (skutecznie przesuwając liczbę z 0 na -1), ponieważ wątek już trzyma blokadę i może "ponownie go" wprowadzić. Zamki również mogą być nierezydentne. Uchwyt blokady powinien wywoływać unlock() taką samą liczbę razy jak lock().

Semafory nie mają pojęcia własności, więc nie mogą być ciągłe, chociaż można uzyskać wiele pozwoleń, które są dostępne. Oznacza to, że wątek musi zostać zablokowany, gdy napotka wartość 0, dopóki ktoś nie zwiększy wartości semafora.

Ponadto, w tym, co widziałem (czyli w Javie), można zwiększyć semafor większy niż N, co również ma związek z własnością: semafor nie ma pojęcia własności, więc każdy może dać mu więcej zezwolenia. W przeciwieństwie do wątku, gdy tylko wątek wywołuje unlock() bez przytrzymywania blokady, jest to błąd. (W java wyrzuci wyjątek).

Mam nadzieję, że ten sposób myślenia o tym pomaga.

16

(Stosując terminologię z java.util.concurrent.Semaphore dany tag Java. Niektóre z tych danych są specyficzne dla implementacji. Podejrzewam, że twój „w dół” jest acquire() metoda semafora Java, a swoje "up" to release().)

Tak, twoje ostatnie połączenie z acquire() zablokuje się, dopóki inny wątek nie zadzwoni pod numer release() lub wątek zostanie przerwany.

Tak, można dzwonić pod numer release() więcej razy, a następnie w dół więcej razy - przynajmniej z numerem java.util.concurrent.Semaphore.

Niektóre inne implementacje semafora mogą mieć pojęcie "maksymalnej" liczby zezwoleń, a wezwanie do wydania poza to maksimum zakończy się niepowodzeniem. Klasa Java Semaphore umożliwia odwrotną sytuację, w której semafor może zaczynać się od ujemnej liczby zezwoleń, a wszystkie wywołania acquire() zakończą się niepowodzeniem, dopóki nie będzie wystarczającej liczby wywołań release(). Gdy liczba pozwoleń stanie się nieujemna, nigdy już nie będzie ujemna.

+0

Czy można bezpiecznie powiedzieć, że negatywny semafor działa jak odliczanie w dół? Efektywnie nic nie mogę zrobić, gdy osiągnięte zostanie ostatnie wydanie (Count = 0). Czy są jakieś inne przypadki, w których chciałbym użyć negatywnego semafora? – jtkSource

+0

@jtkSource: Nie znam jednego offhandu. –

1

Po prostu zobacz N jako licznik, który liczy twoje ograniczone zasoby. Ponieważ nie można mieć ujemnej liczby zasobów, N pozostaje> = 0. Jeśli liczba dostępnych zasobów ulegnie zmianie, należy również zmienić maksymalną wartość N. Nie uważam za dobry styl, aby inkrementować n bez uprzedniego zmniejszenia go w żadnym innym przypadku.

2

Tak, wartość ujemna oznacza, że ​​są procesy oczekujące na zwolnienie semafora. Wartość dodatnia oznacza, że ​​możesz wywoływać nabycie tyle razy, zanim semafor się zablokuje.

Można myśleć o wartości w ten sposób: liczba dodatnia oznacza, że ​​dostępnych jest wiele zasobów. Wartość ujemna oznacza, że ​​istnieje wiele podmiotów potrzebujących zasobu, gdy wszystkie zasoby są pobierane w danym momencie. Gdy zdobędziesz zasób, który obniżysz wartość, po jej zwolnieniu zwiększasz wartość. Jeśli po dekrementacji wartość wynosi nadal> = 0, otrzymasz zasób, w przeciwnym razie twoja jednostka zostanie umieszczona w kolejce.

Miły wyjaśnienie semaforów w Wikipedii: http://en.wikipedia.org/wiki/Semaphore_(programming)

8

Cześć Greg rozważyć następujący przykład:

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

Jeśli widzisz wyjście będzie u get następujący:

Acquire: 0 Wydano: 1 Wydano: 2 Wydano: 3 Zezwolono: 4 Uzyskaj: 3 Uzyskaj: 2 Uzyskaj: 1 Uzyskaj: 0 I czekać będzie.

Więc w zasadzie pozwolić wzrośnie w każdym wydaniu i nabyć będzie się zmniejszać aż 0. Gdy dotarł 0 będzie czekać aż do uwolnienia nazywany jest na tym samym obiekcie :)

0

Korzystanie z java.util.concurrent.Semaphore metody acquire() i release(), uważam, że zezwolenia zawsze będą> = 0. Powiedzmy, że chcesz zsynchronizować wątki, aby w pętli znajdował się tylko jeden wątek. Jeśli sem jest typem Semaphore, który ma wartość początkową 1, nie będzie działać dla więcej niż 2 wątków.

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 } 

Można jednak zaimplementować klasę Semaphore z języka Java i utworzyć własną klasę, która na to pozwala.

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

} 

Teraz val może być ujemny. Jednak nie jestem pewien, czy jest to całkowicie bezpieczne, ponieważ jeśli mamy sygnał z jednego wątku i czekamy od drugiego, a oni spróbują wartości val ++ i val - może to być złe. (szanse na to są bardzo małe, ale istnieją, więc jeśli kodujesz i musisz być w 100% bezbłędny, nie polecam używania tego kodu) Podsumowując, dlatego lepiej jest używać koncepcji monitorów w java i słowo kluczowe zsynchronizowane.