信号量可以低于0吗?我的意思是说,我有一个N = 3的信号量,我称之为“向下”4次,然后N将保持为0但是一个进程将被阻止?
另一方面,如果在一开始我打电话,N可以高于3吗?因为正如我所看到的那样,如果在开始时N可以高于3,我会调用几次,然后我可以调用更多次,因此在关键部分放入更多进程然后信号量允许我
如果有人为我澄清一点,我会非常感激。
格雷格
答案 0 :(得分:17)
(使用Java.util.concurrent.Semaphore中给出Java标记的术语。其中一些细节是特定于实现的。我怀疑你的“down”是Java信号量的acquire()
方法,而你的“up” “是release()
。)
是的,您对acquire()
的最后一次调用将会阻塞,直到另一个线程调用release()
或您的线程被中断。
是的,您可以多次拨打release()
,然后再拨打更多时间 - 至少使用java.util.concurrent.Semaphore
。
信号量的某些其他实现可能具有“最大”许可数量的概念,并且超出该最大值的释放调用将失败。 Java Semaphore
类允许相反的情况,信号量可以从允许的负数开始,并且所有acquire()
调用都将失败,直到有足够的release()
次调用。一旦许可证的数量变为非负数,它就不会再次变为负数。
答案 1 :(得分:8)
嗨格雷格考虑以下例子:
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());
}
如果您看到输出,您将获得以下信息:
Acquire : 0
Released : 1
Released : 2
Released : 3
Released : 4
Acquire : 3
Acquire : 2
Acquire : 1
Acquire : 0
等待继续。
所以基本上许可将在每次发布时增加,并且获得将减少直到0。 一旦它达到0,它将等待直到在同一个对象上调用release :)
答案 2 :(得分:6)
当它为0时调用不应该工作。在3的时候调用它确实有效。 (我在想Java)。
让我再补充一点。许多人会想到像(二进制)信号量这样的锁(即 - N = 1,因此信号量的值为0(保持)或1(不保持))。但这不太对。锁具有“所有权”的概念,因此它可能是“可重入的”。这意味着一个持有锁的线程被允许再次调用lock()(有效地将计数从0移动到-1),因为线程已经持有锁并被允许“重新进入”它。锁也可以是不可重入的。锁定持有者应该与lock()调用unlock()次数相同。
信号量没有所有权的概念,所以它们不能是可重入的,尽管可以获得许多许可证。这意味着线程在遇到值0时需要阻塞,直到某人增加信号量为止。
另外,在我所看到的(也就是Java)中,你可以增加大于N的信号量,这也与所有权有关:信号量没有所有权的概念所以任何人都可以给它更多的许可。与线程不同,每当线程调用unlock()而不持有锁时,这就是错误。 (在java中它会引发异常)。
希望这种思考方式有所帮助。
答案 3 :(得分:2)
是的,负值意味着您有等待释放信号量的进程。正值意味着您可以在信号量阻塞之前多次调用获取。
您可以通过这种方式考虑价值:正数表示可用的资源很多。负值意味着当目前采用所有资源时,有许多实体需要资源。当您获取资源时,您会减小该值,当您释放它时,您会增加该值。如果在减量后值仍为> = 0,则获得资源,否则您的实体将被放入队列。
维基百科中信号量的一个很好的解释: http://en.wikipedia.org/wiki/Semaphore_(programming)
答案 4 :(得分:1)
只需将N视为计算有限资源的计数器。由于您不能拥有负数资源,因此N保持> = 0.如果可用资源的数量发生变化,则必须更改最大N.在任何其他情况下,我不会认为增加n而不先递减n的好方式。
答案 5 :(得分:0)
将java.util.concurrent.Semaphore
与方法acquire()
和release()
一起使用,我认为许可证始终为>=0
。让我们假设你想要同步线程,这样只有一个线程可以在for循环中。如果sem是具有初始值1的Semaphore
类型,则对于超过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实现Semaphore类,并创建自己的类来实现此目的。
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和关键字同步中使用监视器的概念更好的原因。