信号量如何工作?

时间:2009-08-03 09:02:20

标签: java multithreading computer-science semaphore

信号量可以低于0吗?我的意思是说,我有一个N = 3的信号量,我称之为“向下”4次,然后N将保持为0但是一个进程将被阻止?

另一方面,如果在一开始我打电话,N可以高于3吗?因为正如我所看到的那样,如果在开始时N可以高于3,我会调用几次,然后我可以调用更多次,因此在关键部分放入更多进程然后信号量允许我

如果有人为我澄清一点,我会非常感激。

格雷格

6 个答案:

答案 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和关键字同步中使用监视器的概念更好的原因。