信号量如何工作?

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

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

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

格雷格

当它为0时调用不应该工作。 在3的时候调用它确实有效。 (我在想Java)。

让我再补充一点。 许多人会想到像(二进制)信号量这样的锁(即 – N = 1,因此信号量的值为0(保持)或1(不保持))。 但这不太对。 锁具有“所有权”的概念,因此它可能是“可重入的”。 这意味着一个持有锁的线程被允许再次调用lock()(有效地将计数从0移动到-1),因为线程已经持有锁并被允许“重新进入”它。 锁也可以是不可重入的。 锁定持有者应该与lock()调用unlock()的次数相同。

信号量没有所有权的概念,所以它们不能是可重入的,尽管可以获得许多可用的许可。 这意味着线程在遇到值0时需要阻塞,直到有人递增信号量为止。

另外,在我所看到的(也就是Java)中,你可以增加大于N的信号量,这也与所有权有关:信号量没有所有权的概念所以任何人都可以给它更多的许可。 与线程不同,每当线程调用unlock()而不保持锁定时,这就是错误。 (在java中它将引发exception)。

希望这种思考方式有所帮助。

(使用给定Java标记的java.util.concurrent.Semaphore中的术语。其中一些细节是特定于实现的。我怀疑你的“down”是Java信号量的acquire()方法,而你的“up”是release() 。)

是的,你对acquire()最后一次调用将阻塞,直到另一个线程调用release()或你的线程被中断。

是的,您可以多次调用release() ,然后调用更多次 – 至少使用java.util.concurrent.Semaphore

信号量的一些其他实现可能具有“最大”许可数量的概念,并且超出该最大值的释放调用将失败。 Java Semaphore类允许相反的情况,其中信号量可以以负数许可开始,并且所有acquire()调用将失败,直到有足够的release()调用。 一旦许可证的数量变为非负数,它将永远不会再次变为负数。

嗨格雷格考虑以下例子:

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()); } 

如果你看到输出你会得到以下:

获取:0已发布:1已发布:2已发布:3已发布:4已获取:3获取:2获取:1获取:0等待正在进行中。

因此基本上许可将在每个版本上增加并且获取将减少它直到0.一旦它达到0它将等待直到在相同对象上调用release 🙂

是的,负值意味着您有等待释放信号量的进程。 正值意味着您可以在信号量阻塞之前多次调用获取。

您可以通过这种方式考虑价值:正数意味着有许多可用资源。 负值意味着当目前采用所有资源时,有许多实体需要资源。 当您获取资源时,您会减小该值,当您释放它时,您会增加该值。 如果在减量后值仍然> = 0,则获得资源,否则您的实体将被放入队列中。

维基百科中信号量的一个很好的解释: http : //en.wikipedia.org/wiki/Semaphore_ (programming)

只需将N视为计算有限资源的计数器。 由于您不能拥有负数资源,因此N保持> = 0.如果可用资源的数量发生变化,则还必须更改最大N. 在任何其他情况下,我不会认为增加n而不先减少它是好的风格。

使用带有方法acquire()和release()的java.util.concurrent.Semaphore,我认为许可证总是> = 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实现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和关键字同步。