我什么时候应该使用信号量?

Yoc*_*mer 9 multithreading semaphore locking thread-safety

什么时候会使用信号量?

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

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

Ale*_*nov 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
Run Code Online (Sandbox Code Playgroud)

第一个问题是信号量不能保护池不被多个线程访问.因此,需要另一种保护.让它成为一把锁:

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
Run Code Online (Sandbox Code Playgroud)

需要采取其他措施以确保访问时池不为空.从技术上讲,可以绕过信号量访问池,但它会破坏上面的采集过程的资源可用性保证.因此,只能通过该过程访问池.

到目前为止一切都那么好,但如果一个线程不想被动地等待资源呢?是否可以支持非阻塞资源获取?如果信号量本身支持非阻塞采集,那很容易; 否则(例如在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
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,它甚至不需要访问条件变量,并且不会对阻塞情况造成损害.对我而言,它明显优于使用信号量.