Как работает семафор?
может ли семафор быть ниже 0? Я имею в виду, скажем, у меня есть семафор с N=3, и я вызываю "вниз" 4 раза, тогда N останется 0, но один процесс будет заблокирован?
и то же самое с другой стороны, если в начале я вызываю, может ли N быть выше 3? Потому что, как я вижу, если N может быть выше 3, Если в начале я вызываю пару раз, то позже я мог бы вызывать больше раз, чем могу, таким образом, помещая больше процессов в критический раздел, тогда семафор позволяет мне.
Если кто-то прояснит это немного для меня, я буду очень признателен.
Грег
6 ответов
вызов вниз, когда это 0 не должно работать. Звоню, когда он 3 работает. (Я думаю о Java).
позвольте мне добавить еще несколько. Многие люди думают о замках, таких как (двоичные) семафоры (т. е. - N = 1, поэтому значение семафора равно 0 (удерживается) или 1 (не удерживается)). Но это не совсем так. Замок имеет понятие "право собственности", так что это может быть "повторно". Это означает, что потоку, который содержит блокировку, разрешено снова вызывать lock () (эффективно перемещая счетчик от 0 до -1), потому что нить уже удерживает блокировку и позволяет "повторно войти" в нее. Замки могут также быть non reentrant. Ожидается, что держатель замка вызовет unlock () столько же раз, сколько и lock ().
семафоры имею понятия собственности, поэтому они не могут быть реентерабельным, хотя столько разрешений, как доступны могут быть приобретены. Это означает, что поток должен блокировать, когда он сталкивается со значением 0, пока кто-то не увеличит семафор.
кроме того, в том, что я видел (это Java), вы можете увеличить семафор больше N, и это также имеет отношение к собственности: семафор не имеет понятия о собственности, поэтому каждый может дать ему больше разрешений. В отличие от потока, где всякий раз, когда поток вызывает unlock() без блокировки, это ошибка. (В java это вызовет исключение).
надеюсь, этот способ мышления об этом поможет.
(используя терминологию из java.утиль.параллельный.Семафор, заданный Java-тегом. Некоторые из этих деталей реализации. Я подозреваю, что ваш "вниз" - это семафор Java acquire()
метод, и ваш "вверх" является release()
.)
Да, ваш последний вызов acquire()
будет блокировать, пока другой поток вызывает release()
или ваш поток прерывается.
Да, вы можете позвонить release()
еще раз, потом еще раз - по крайней мере с java.util.concurrent.Semaphore
.
некоторые другие реализация семафора может иметь представление о "максимальном" количестве разрешений, и вызов выпустить за пределы этого максимума потерпит неудачу. В Java Semaphore
класс допускает обратную ситуацию, когда семафор может начинаться с отрицательного количества разрешений, и все acquire()
вызовы будут терпеть неудачу, пока не будет достаточно release()
звонки. Как только количество разрешений станет неотрицательным, оно никогда не станет отрицательным снова.
Привет, Грег рассмотрим следующий пример :
public static void main (String [] args) вызывает исключение 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());
}
Если вы видите выход u, вы получите следующее:
приобретет : 0 Выпущено : 1 Дата выпуска : 2 Выпущен : 3 Выпущен : 4 Приобрести : 3 Приобрести : 2 Приобретение : 1 Приобрести : 0 И ожидание продолжается.
поэтому в основном разрешение будет увеличиваться на каждом выпуске и приобретать уменьшит его до 0. Как только он достигнет 0, он будет ждать пока релиз вызывается на том же объекте:)
да, отрицательное значение означает, что у вас есть процессы, ожидающие освобождения семафора. Положительное значение означает, что вы можете вызвать приобрести это много раз до семафорных блоков.
вы могли бы подумать о ценности таким образом: положительное число означает, что многие ресурсы доступны. Отрицательное значение означает, что многие сущности нуждаются в ресурсе, когда все ресурсы взяты в данный момент. Когда вы приобретаете ресурс, вы уменьшаете значение, когда вы выпускаете это вы увеличиваете ценность. Если значение по-прежнему >= 0 после уменьшения, вы получаете ресурс, иначе ваша сущность помещается в очередь.
хорошее объяснение семафоров в Википедии: http://en.wikipedia.org/wiki/Semaphore_ (Программирование)
просто см. N как счетчик, который подсчитывает ваш ограниченный ресурс. Поскольку у вас не может быть отрицательного количества ресурсов, N остается >= 0. Если количество доступных ресурсов изменяется, то должно быть изменено и максимальное N. Я бы не счел хорошим стилем увеличивать n, не уменьшая его сначала в любом другом случае.
использование java.утиль.параллельный.Семафор с методами acquire () и release (), я думаю, разрешения всегда будут >=0. Предположим, вы хотите синхронизировать потоки, чтобы только 1 поток мог быть внутри цикла for. Если sem является типом семафора, который имеет начальное значение 1, это не будет работать для более чем 2 потоков.
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 }
однако вы можете реализовать класс семафора из java и сделать свой собственный класс, который позволяет это.
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++;
}
}
}
теперь val может быть отрицательным. Однако Я я не уверен, что это полностью безопасно, потому что если у нас есть сигнал от одного потока и ждать от другого, и они пытаются val++ и val-это может быть плохо. (шансы на это очень малы, но все же они существуют, поэтому, если вы кодируете, и вы должны быть 100% без ошибок, я не рекомендую использовать этот код ) В заключение вот почему лучше использовать концепцию мониторов в java и синхронизировать ключевое слово.