Когда можно использовать семафоры?
Только пример, о котором я могу думать, - это ограничение количества потоков, обращающихся к тем же данным/коду одновременно...
Любые другие сценарии, в которых наилучшим решением будут семафоры?
Когда можно использовать семафоры?
Только пример, о котором я могу думать, - это ограничение количества потоков, обращающихся к тем же данным/коду одновременно...
Любые другие сценарии, в которых наилучшим решением будут семафоры?
Семафоры могут быть подходящими для сигнализации между процессами. Для многопоточного программирования семафоров следует избегать. Если вам нужен эксклюзивный доступ к ресурсу, используйте мьютекс. Если вам нужно ждать сигнала, используйте переменную условия.
Даже наиболее часто упоминаемый случай пула ресурсов может быть проще и безопаснее реализован с переменной состояния, чем с семафором. Давайте посмотрим на этот случай. Наивная реализация с семафором будет выглядеть как (псевдокод):
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
Как вы можете видеть, ему даже не нужно обращаться к переменной условия и не наносит вреда делу блокировки. Для меня это явно превосходит использование семафора.
Пулы соединений.
т.е. у вас есть 20 соединений и 150 потоков. В этом случае у вас будет семафор для контроля доступа к 20 соединениям.
Семафоры могут быть приобретены одним потоком и выпущены в другом. Замки обычно не могут этого сделать. Я использовал это, когда поток A заканчивает использование ресурса и передает управление ресурсом потоку B. Мне пришлось контролировать порядок, чтобы избежать тупиков в этой конкретной ситуации.