什么时候会使用信号量?
我能想到的唯一例子是限制同时访问相同数据/代码的线程数...
信号量是最佳解决方案的任何其他方案?
答案 0 :(得分: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
正如您所看到的,它甚至不需要访问条件变量,也不会对阻塞情况造成损害。对我而言,它明显优于使用信号量。
答案 1 :(得分:4)
连接池。
即。你有20个连接和150个线程。在这种情况下,您将拥有一个信号量来控制对20个连接的访问。
答案 2 :(得分:2)
信号量可以通过一个线程获取并在另一个线程中释放。锁通常不能这样做。我已经在线程A完成使用资源并将资源的控制权传递给线程B时使用了这个。我必须控制顺序以避免在这种特殊情况下出现死锁。