【问题标题】:When should I use semaphores?什么时候应该使用信号量?
【发布时间】:2011-04-08 20:18:52
【问题描述】:

什么时候会使用信号量?

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

信号量是最佳解决方案的任何其他场景?

【问题讨论】:

标签: multithreading locking thread-safety semaphore


【解决方案1】:

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

即使是最常提到的资源池案例,使用条件变量也可以比使用信号量更简单、更安全地实现。我们来看看这个案例。带有信号量的简单实现看起来像(伪代码):

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

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

【讨论】:

    【解决方案2】:

    连接池。

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

    【讨论】:

    • +1:很好的简单示例,但我想知道信号量是否适用于其他任何情况......
    【解决方案3】:

    信号量可以由一个线程获取并在另一个线程中释放。锁通常不能做到这一点。当线程 A 完成使用资源并将资源的控制权传递给线程 B 时,我使用了此方法。在这种特殊情况下,我必须控制顺序以避免死锁。

    【讨论】:

      猜你喜欢
      • 2011-05-01
      • 2016-06-27
      • 1970-01-01
      • 1970-01-01
      • 2023-04-02
      • 2011-04-15
      • 2017-04-10
      • 2012-03-19
      • 2018-05-12
      相关资源
      最近更新 更多