164 lines
5.0 KiB
Ruby
164 lines
5.0 KiB
Ruby
require 'concurrent/atomic/mutex_semaphore'
|
|
|
|
module Concurrent
|
|
|
|
###################################################################
|
|
|
|
# @!macro semaphore_method_initialize
|
|
#
|
|
# Create a new `Semaphore` with the initial `count`.
|
|
#
|
|
# @param [Fixnum] count the initial count
|
|
#
|
|
# @raise [ArgumentError] if `count` is not an integer
|
|
|
|
# @!macro semaphore_method_acquire
|
|
#
|
|
# Acquires the given number of permits from this semaphore,
|
|
# blocking until all are available. If a block is given,
|
|
# yields to it and releases the permits afterwards.
|
|
#
|
|
# @param [Fixnum] permits Number of permits to acquire
|
|
#
|
|
# @raise [ArgumentError] if `permits` is not an integer or is less than zero
|
|
#
|
|
# @return [nil, BasicObject] Without a block, `nil` is returned. If a block
|
|
# is given, its return value is returned.
|
|
|
|
# @!macro semaphore_method_available_permits
|
|
#
|
|
# Returns the current number of permits available in this semaphore.
|
|
#
|
|
# @return [Integer]
|
|
|
|
# @!macro semaphore_method_drain_permits
|
|
#
|
|
# Acquires and returns all permits that are immediately available.
|
|
#
|
|
# @return [Integer]
|
|
|
|
# @!macro semaphore_method_try_acquire
|
|
#
|
|
# Acquires the given number of permits from this semaphore,
|
|
# only if all are available at the time of invocation or within
|
|
# `timeout` interval. If a block is given, yields to it if the permits
|
|
# were successfully acquired, and releases them afterward, returning the
|
|
# block's return value.
|
|
#
|
|
# @param [Fixnum] permits the number of permits to acquire
|
|
#
|
|
# @param [Fixnum] timeout the number of seconds to wait for the counter
|
|
# or `nil` to return immediately
|
|
#
|
|
# @raise [ArgumentError] if `permits` is not an integer or is less than zero
|
|
#
|
|
# @return [true, false, nil, BasicObject] `false` if no permits are
|
|
# available, `true` when acquired a permit. If a block is given, the
|
|
# block's return value is returned if the permits were acquired; if not,
|
|
# `nil` is returned.
|
|
|
|
# @!macro semaphore_method_release
|
|
#
|
|
# Releases the given number of permits, returning them to the semaphore.
|
|
#
|
|
# @param [Fixnum] permits Number of permits to return to the semaphore.
|
|
#
|
|
# @raise [ArgumentError] if `permits` is not a number or is less than zero
|
|
#
|
|
# @return [nil]
|
|
|
|
###################################################################
|
|
|
|
# @!macro semaphore_public_api
|
|
#
|
|
# @!method initialize(count)
|
|
# @!macro semaphore_method_initialize
|
|
#
|
|
# @!method acquire(permits = 1)
|
|
# @!macro semaphore_method_acquire
|
|
#
|
|
# @!method available_permits
|
|
# @!macro semaphore_method_available_permits
|
|
#
|
|
# @!method drain_permits
|
|
# @!macro semaphore_method_drain_permits
|
|
#
|
|
# @!method try_acquire(permits = 1, timeout = nil)
|
|
# @!macro semaphore_method_try_acquire
|
|
#
|
|
# @!method release(permits = 1)
|
|
# @!macro semaphore_method_release
|
|
|
|
###################################################################
|
|
|
|
# @!visibility private
|
|
# @!macro internal_implementation_note
|
|
SemaphoreImplementation = if Concurrent.on_jruby?
|
|
require 'concurrent/utility/native_extension_loader'
|
|
JavaSemaphore
|
|
else
|
|
MutexSemaphore
|
|
end
|
|
private_constant :SemaphoreImplementation
|
|
|
|
# @!macro semaphore
|
|
#
|
|
# A counting semaphore. Conceptually, a semaphore maintains a set of
|
|
# permits. Each {#acquire} blocks if necessary until a permit is
|
|
# available, and then takes it. Each {#release} adds a permit, potentially
|
|
# releasing a blocking acquirer.
|
|
# However, no actual permit objects are used; the Semaphore just keeps a
|
|
# count of the number available and acts accordingly.
|
|
# Alternatively, permits may be acquired within a block, and automatically
|
|
# released after the block finishes executing.
|
|
#
|
|
# @!macro semaphore_public_api
|
|
# @example
|
|
# semaphore = Concurrent::Semaphore.new(2)
|
|
#
|
|
# t1 = Thread.new do
|
|
# semaphore.acquire
|
|
# puts "Thread 1 acquired semaphore"
|
|
# end
|
|
#
|
|
# t2 = Thread.new do
|
|
# semaphore.acquire
|
|
# puts "Thread 2 acquired semaphore"
|
|
# end
|
|
#
|
|
# t3 = Thread.new do
|
|
# semaphore.acquire
|
|
# puts "Thread 3 acquired semaphore"
|
|
# end
|
|
#
|
|
# t4 = Thread.new do
|
|
# sleep(2)
|
|
# puts "Thread 4 releasing semaphore"
|
|
# semaphore.release
|
|
# end
|
|
#
|
|
# [t1, t2, t3, t4].each(&:join)
|
|
#
|
|
# # prints:
|
|
# # Thread 3 acquired semaphore
|
|
# # Thread 2 acquired semaphore
|
|
# # Thread 4 releasing semaphore
|
|
# # Thread 1 acquired semaphore
|
|
#
|
|
# @example
|
|
# semaphore = Concurrent::Semaphore.new(1)
|
|
#
|
|
# puts semaphore.available_permits
|
|
# semaphore.acquire do
|
|
# puts semaphore.available_permits
|
|
# end
|
|
# puts semaphore.available_permits
|
|
#
|
|
# # prints:
|
|
# # 1
|
|
# # 0
|
|
# # 1
|
|
class Semaphore < SemaphoreImplementation
|
|
end
|
|
end
|