何时应该使用信号量?

9

什么时候需要使用信号量?

我能想到的唯一例子就是限制同时访问相同数据/代码的线程数量...

还有其他情况下,信号量会是最好的解决方案吗?


2
相关:https://dev59.com/EnE95IYBdhLWcg3wWMhQ - Travis Gockel
一个例子:http://stackoverflow.com/questions/2375132/releasesemaphore-does-not-release-the-semaphore/2375370#2375370 - Jerry Coffin
3个回答

5

信号量可能适用于进程间的信号传递。但在多线程编程中,应避免使用信号量。如果需要对资源进行独占访问,请使用互斥锁。如果需要等待信号,请使用条件变量。

即使是最常见的资源池案例,也可以通过条件变量比信号量更简单、更安全地实现。让我们看看这种情况。使用信号量的天真实现将如下(伪代码):

wait for semaphore to open
take a resource out of the pool
use the resource
put it back to the pool
open the semaphore for one more thread

第一个问题是信号量并不能保护池免受多个线程的访问。因此,需要另一种保护措施。让它成为锁:

wait for semaphore to open
acquire the lock for the pool
take a resource out of the pool
release the lock
use the resource
acquire the lock
put the resource back to the pool
release the lock
open the semaphore for one more thread

需要采取额外措施来确保访问时池不为空。从技术上讲,可以绕过信号量访问池,但这将破坏上述获取过程的资源可用性保证。因此,应该只通过该过程访问池。
到目前为止还不错,但是如果一个线程不想被动地等待资源怎么办?是否支持非阻塞式资源获取?如果信号量本身支持非阻塞获取,则很容易实现;否则(例如在Windows上),这将成为一个问题。信号量不能被绕过,因为它会破坏阻塞情况。仅当池不为空时通过信号量可能会导致死锁,如果在锁下执行,则检查是否为空的结果一旦释放锁就变得无用了。这可能是可行的(我没有尝试过),但肯定会增加显着的额外复杂性。
使用条件变量,这个问题可以轻松解决。以下是具有阻塞获取的伪代码:
acquire the lock
while the resource pool is empty,
    wait for condition variable to be signaled
take a resource out of the pool
release the lock
use the resource
acquire the lock
put the resource back to the pool
release the lock
signal the condition variable

在这种情况下,添加非阻塞获取没有问题:

acquire the lock
if the resource pool is not empty,
    take a resource out of the pool
release the lock
if the pool was empty, return

如您所见,它甚至不需要访问条件变量,并且对阻塞情况没有任何影响。对我来说,它明显优于使用信号量。


4

连接池。

即,您有20个连接和150个线程。在这种情况下,您将拥有一个信号量来控制对这20个连接的访问。


+1:很好的简单示例,但我想知道是否还有其他情况适合使用信号量... - Yochai Timmer

2

信号量可以被一个线程获取,也可以由另一个线程释放。而锁通常无法实现这一点。我在将资源的控制权从线程A传递给线程B时使用了这个功能。在这种特殊情况下,我必须控制顺序以避免死锁。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接