concurrent-ruby 0.9.2-java → 1.0.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +49 -1
- data/README.md +86 -120
- data/lib/concurrent.rb +14 -5
- data/lib/concurrent/agent.rb +587 -0
- data/lib/concurrent/array.rb +39 -0
- data/lib/concurrent/async.rb +296 -149
- data/lib/concurrent/atom.rb +135 -45
- data/lib/concurrent/atomic/abstract_thread_local_var.rb +38 -0
- data/lib/concurrent/atomic/atomic_boolean.rb +83 -118
- data/lib/concurrent/atomic/atomic_fixnum.rb +101 -163
- data/lib/concurrent/atomic/atomic_reference.rb +1 -8
- data/lib/concurrent/atomic/count_down_latch.rb +62 -103
- data/lib/concurrent/atomic/cyclic_barrier.rb +3 -1
- data/lib/concurrent/atomic/event.rb +1 -1
- data/lib/concurrent/atomic/java_count_down_latch.rb +39 -0
- data/lib/concurrent/atomic/java_thread_local_var.rb +50 -0
- data/lib/concurrent/atomic/mutex_atomic_boolean.rb +60 -0
- data/lib/concurrent/atomic/mutex_atomic_fixnum.rb +91 -0
- data/lib/concurrent/atomic/mutex_count_down_latch.rb +43 -0
- data/lib/concurrent/atomic/mutex_semaphore.rb +115 -0
- data/lib/concurrent/atomic/read_write_lock.rb +5 -4
- data/lib/concurrent/atomic/reentrant_read_write_lock.rb +3 -1
- data/lib/concurrent/atomic/ruby_thread_local_var.rb +172 -0
- data/lib/concurrent/atomic/semaphore.rb +84 -178
- data/lib/concurrent/atomic/thread_local_var.rb +65 -294
- data/lib/concurrent/atomic_reference/jruby+truffle.rb +1 -0
- data/lib/concurrent/atomic_reference/jruby.rb +1 -1
- data/lib/concurrent/atomic_reference/mutex_atomic.rb +14 -8
- data/lib/concurrent/atomic_reference/ruby.rb +1 -1
- data/lib/concurrent/atomics.rb +7 -37
- data/lib/concurrent/collection/copy_on_notify_observer_set.rb +7 -15
- data/lib/concurrent/collection/copy_on_write_observer_set.rb +7 -15
- data/lib/concurrent/collection/java_non_concurrent_priority_queue.rb +84 -0
- data/lib/concurrent/collection/map/atomic_reference_map_backend.rb +927 -0
- data/lib/concurrent/collection/map/mri_map_backend.rb +66 -0
- data/lib/concurrent/collection/map/non_concurrent_map_backend.rb +144 -0
- data/lib/concurrent/collection/map/synchronized_map_backend.rb +86 -0
- data/lib/concurrent/collection/non_concurrent_priority_queue.rb +143 -0
- data/lib/concurrent/collection/ruby_non_concurrent_priority_queue.rb +150 -0
- data/lib/concurrent/concern/dereferenceable.rb +9 -24
- data/lib/concurrent/concern/logging.rb +1 -1
- data/lib/concurrent/concern/obligation.rb +11 -20
- data/lib/concurrent/concern/observable.rb +38 -13
- data/lib/concurrent/configuration.rb +23 -152
- data/lib/concurrent/constants.rb +8 -0
- data/lib/concurrent/delay.rb +14 -12
- data/lib/concurrent/exchanger.rb +339 -41
- data/lib/concurrent/executor/abstract_executor_service.rb +134 -0
- data/lib/concurrent/executor/executor_service.rb +23 -359
- data/lib/concurrent/executor/immediate_executor.rb +3 -2
- data/lib/concurrent/executor/java_executor_service.rb +100 -0
- data/lib/concurrent/executor/java_single_thread_executor.rb +3 -3
- data/lib/concurrent/executor/java_thread_pool_executor.rb +3 -4
- data/lib/concurrent/executor/ruby_executor_service.rb +78 -0
- data/lib/concurrent/executor/ruby_single_thread_executor.rb +10 -66
- data/lib/concurrent/executor/ruby_thread_pool_executor.rb +25 -22
- data/lib/concurrent/executor/safe_task_executor.rb +6 -7
- data/lib/concurrent/executor/serial_executor_service.rb +34 -0
- data/lib/concurrent/executor/serialized_execution.rb +10 -33
- data/lib/concurrent/executor/serialized_execution_delegator.rb +28 -0
- data/lib/concurrent/executor/simple_executor_service.rb +1 -10
- data/lib/concurrent/executor/single_thread_executor.rb +20 -10
- data/lib/concurrent/executor/timer_set.rb +8 -10
- data/lib/concurrent/executors.rb +12 -2
- data/lib/concurrent/future.rb +6 -4
- data/lib/concurrent/hash.rb +35 -0
- data/lib/concurrent/immutable_struct.rb +5 -1
- data/lib/concurrent/ivar.rb +12 -16
- data/lib/concurrent/lazy_register.rb +11 -8
- data/lib/concurrent/map.rb +180 -0
- data/lib/concurrent/maybe.rb +6 -3
- data/lib/concurrent/mutable_struct.rb +7 -6
- data/lib/concurrent/mvar.rb +26 -2
- data/lib/concurrent/{executor/executor.rb → options.rb} +5 -29
- data/lib/concurrent/promise.rb +7 -5
- data/lib/concurrent/scheduled_task.rb +13 -71
- data/lib/concurrent/settable_struct.rb +5 -4
- data/lib/concurrent/synchronization.rb +15 -3
- data/lib/concurrent/synchronization/abstract_lockable_object.rb +98 -0
- data/lib/concurrent/synchronization/abstract_object.rb +7 -146
- data/lib/concurrent/synchronization/abstract_struct.rb +2 -3
- data/lib/concurrent/synchronization/condition.rb +6 -4
- data/lib/concurrent/synchronization/jruby_lockable_object.rb +13 -0
- data/lib/concurrent/synchronization/jruby_object.rb +44 -0
- data/lib/concurrent/synchronization/lock.rb +3 -2
- data/lib/concurrent/synchronization/lockable_object.rb +72 -0
- data/lib/concurrent/synchronization/mri_lockable_object.rb +71 -0
- data/lib/concurrent/synchronization/mri_object.rb +43 -0
- data/lib/concurrent/synchronization/object.rb +140 -73
- data/lib/concurrent/synchronization/rbx_lockable_object.rb +65 -0
- data/lib/concurrent/synchronization/rbx_object.rb +30 -73
- data/lib/concurrent/synchronization/volatile.rb +34 -0
- data/lib/concurrent/thread_safe/synchronized_delegator.rb +50 -0
- data/lib/concurrent/thread_safe/util.rb +14 -0
- data/lib/concurrent/thread_safe/util/adder.rb +74 -0
- data/lib/concurrent/thread_safe/util/array_hash_rbx.rb +30 -0
- data/lib/concurrent/thread_safe/util/cheap_lockable.rb +118 -0
- data/lib/concurrent/thread_safe/util/power_of_two_tuple.rb +38 -0
- data/lib/concurrent/thread_safe/util/striped64.rb +241 -0
- data/lib/concurrent/thread_safe/util/volatile.rb +75 -0
- data/lib/concurrent/thread_safe/util/xor_shift_random.rb +50 -0
- data/lib/concurrent/timer_task.rb +3 -4
- data/lib/concurrent/tuple.rb +86 -0
- data/lib/concurrent/tvar.rb +5 -1
- data/lib/concurrent/utility/at_exit.rb +1 -1
- data/lib/concurrent/utility/engine.rb +4 -0
- data/lib/concurrent/utility/monotonic_time.rb +3 -4
- data/lib/concurrent/utility/native_extension_loader.rb +50 -30
- data/lib/concurrent/version.rb +2 -2
- data/lib/concurrent_ruby_ext.jar +0 -0
- metadata +47 -12
- data/lib/concurrent/atomic/condition.rb +0 -78
- data/lib/concurrent/collection/priority_queue.rb +0 -360
- data/lib/concurrent/synchronization/java_object.rb +0 -34
- data/lib/concurrent/synchronization/monitor_object.rb +0 -27
- data/lib/concurrent/synchronization/mutex_object.rb +0 -43
- data/lib/concurrent/utilities.rb +0 -5
- data/lib/concurrent/utility/timeout.rb +0 -39
- data/lib/concurrent/utility/timer.rb +0 -26
- data/lib/concurrent_ruby.rb +0 -2
@@ -99,13 +99,15 @@ module Concurrent
|
|
99
99
|
# @!visibility private
|
100
100
|
WRITE_LOCK_MASK = MAX_WRITERS
|
101
101
|
|
102
|
+
safe_initialization!
|
103
|
+
|
102
104
|
# Create a new `ReentrantReadWriteLock` in the unlocked state.
|
103
105
|
def initialize
|
106
|
+
super()
|
104
107
|
@Counter = AtomicFixnum.new(0) # single integer which represents lock state
|
105
108
|
@ReadQueue = Synchronization::Lock.new # used to queue waiting readers
|
106
109
|
@WriteQueue = Synchronization::Lock.new # used to queue waiting writers
|
107
110
|
@HeldCount = ThreadLocalVar.new(0) # indicates # of R & W locks held by this thread
|
108
|
-
ensure_ivar_visibility!
|
109
111
|
end
|
110
112
|
|
111
113
|
# Execute a block operation within a read lock.
|
@@ -0,0 +1,172 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'concurrent/atomic/abstract_thread_local_var'
|
3
|
+
|
4
|
+
module Concurrent
|
5
|
+
|
6
|
+
# @!visibility private
|
7
|
+
# @!macro internal_implementation_note
|
8
|
+
class RubyThreadLocalVar < AbstractThreadLocalVar
|
9
|
+
|
10
|
+
# Each thread has a (lazily initialized) array of thread-local variable values
|
11
|
+
# Each time a new thread-local var is created, we allocate an "index" for it
|
12
|
+
# For example, if the allocated index is 1, that means slot #1 in EVERY
|
13
|
+
# thread's thread-local array will be used for the value of that TLV
|
14
|
+
#
|
15
|
+
# The good thing about using a per-THREAD structure to hold values, rather
|
16
|
+
# than a per-TLV structure, is that no synchronization is needed when
|
17
|
+
# reading and writing those values (since the structure is only ever
|
18
|
+
# accessed by a single thread)
|
19
|
+
#
|
20
|
+
# Of course, when a TLV is GC'd, 1) we need to recover its index for use
|
21
|
+
# by other new TLVs (otherwise the thread-local arrays could get bigger
|
22
|
+
# and bigger with time), and 2) we need to null out all the references
|
23
|
+
# held in the now-unused slots (both to avoid blocking GC of those objects,
|
24
|
+
# and also to prevent "stale" values from being passed on to a new TLV
|
25
|
+
# when the index is reused)
|
26
|
+
# Because we need to null out freed slots, we need to keep references to
|
27
|
+
# ALL the thread-local arrays -- ARRAYS is for that
|
28
|
+
# But when a Thread is GC'd, we need to drop the reference to its thread-local
|
29
|
+
# array, so we don't leak memory
|
30
|
+
|
31
|
+
# @!visibility private
|
32
|
+
FREE = []
|
33
|
+
LOCK = Mutex.new
|
34
|
+
ARRAYS = {} # used as a hash set
|
35
|
+
@@next = 0
|
36
|
+
private_constant :FREE, :LOCK, :ARRAYS
|
37
|
+
|
38
|
+
# @!macro [attach] thread_local_var_method_initialize
|
39
|
+
#
|
40
|
+
# Creates a thread local variable.
|
41
|
+
#
|
42
|
+
# @param [Object] default the default value when otherwise unset
|
43
|
+
def initialize(default = nil)
|
44
|
+
@default = default
|
45
|
+
allocate_storage
|
46
|
+
end
|
47
|
+
|
48
|
+
# @!macro thread_local_var_method_get
|
49
|
+
def value
|
50
|
+
if array = get_threadlocal_array
|
51
|
+
value = array[@index]
|
52
|
+
if value.nil?
|
53
|
+
@default
|
54
|
+
elsif value.equal?(NULL)
|
55
|
+
nil
|
56
|
+
else
|
57
|
+
value
|
58
|
+
end
|
59
|
+
else
|
60
|
+
@default
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# @!macro thread_local_var_method_set
|
65
|
+
def value=(value)
|
66
|
+
me = Thread.current
|
67
|
+
# We could keep the thread-local arrays in a hash, keyed by Thread
|
68
|
+
# But why? That would require locking
|
69
|
+
# Using Ruby's built-in thread-local storage is faster
|
70
|
+
unless array = get_threadlocal_array(me)
|
71
|
+
array = set_threadlocal_array([], me)
|
72
|
+
LOCK.synchronize { ARRAYS[array.object_id] = array }
|
73
|
+
ObjectSpace.define_finalizer(me, self.class.thread_finalizer(array))
|
74
|
+
end
|
75
|
+
array[@index] = (value.nil? ? NULL : value)
|
76
|
+
value
|
77
|
+
end
|
78
|
+
|
79
|
+
# @!macro thread_local_var_method_bind
|
80
|
+
def bind(value, &block)
|
81
|
+
if block_given?
|
82
|
+
old_value = self.value
|
83
|
+
begin
|
84
|
+
self.value = value
|
85
|
+
yield
|
86
|
+
ensure
|
87
|
+
self.value = old_value
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
protected
|
93
|
+
|
94
|
+
# @!visibility private
|
95
|
+
def allocate_storage
|
96
|
+
@index = LOCK.synchronize do
|
97
|
+
FREE.pop || begin
|
98
|
+
result = @@next
|
99
|
+
@@next += 1
|
100
|
+
result
|
101
|
+
end
|
102
|
+
end
|
103
|
+
ObjectSpace.define_finalizer(self, self.class.threadlocal_finalizer(@index))
|
104
|
+
end
|
105
|
+
|
106
|
+
# @!visibility private
|
107
|
+
def self.threadlocal_finalizer(index)
|
108
|
+
proc do
|
109
|
+
LOCK.synchronize do
|
110
|
+
FREE.push(index)
|
111
|
+
# The cost of GC'ing a TLV is linear in the number of threads using TLVs
|
112
|
+
# But that is natural! More threads means more storage is used per TLV
|
113
|
+
# So naturally more CPU time is required to free more storage
|
114
|
+
ARRAYS.each_value do |array|
|
115
|
+
array[index] = nil
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# @!visibility private
|
122
|
+
def self.thread_finalizer(array)
|
123
|
+
proc do
|
124
|
+
LOCK.synchronize do
|
125
|
+
# The thread which used this thread-local array is now gone
|
126
|
+
# So don't hold onto a reference to the array (thus blocking GC)
|
127
|
+
ARRAYS.delete(array.object_id)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
private
|
133
|
+
|
134
|
+
if Thread.instance_methods.include?(:thread_variable_get)
|
135
|
+
|
136
|
+
def get_threadlocal_array(thread = Thread.current)
|
137
|
+
thread.thread_variable_get(:__threadlocal_array__)
|
138
|
+
end
|
139
|
+
|
140
|
+
def set_threadlocal_array(array, thread = Thread.current)
|
141
|
+
thread.thread_variable_set(:__threadlocal_array__, array)
|
142
|
+
end
|
143
|
+
|
144
|
+
else
|
145
|
+
|
146
|
+
def get_threadlocal_array(thread = Thread.current)
|
147
|
+
thread[:__threadlocal_array__]
|
148
|
+
end
|
149
|
+
|
150
|
+
def set_threadlocal_array(array, thread = Thread.current)
|
151
|
+
thread[:__threadlocal_array__] = array
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
# This exists only for use in testing
|
156
|
+
# @!visibility private
|
157
|
+
def value_for(thread)
|
158
|
+
if array = get_threadlocal_array(thread)
|
159
|
+
value = array[@index]
|
160
|
+
if value.nil?
|
161
|
+
@default
|
162
|
+
elsif value.equal?(NULL)
|
163
|
+
nil
|
164
|
+
else
|
165
|
+
value
|
166
|
+
end
|
167
|
+
else
|
168
|
+
@default
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
@@ -1,207 +1,113 @@
|
|
1
|
+
require 'concurrent/atomic/mutex_semaphore'
|
1
2
|
require 'concurrent/synchronization'
|
2
3
|
|
3
4
|
module Concurrent
|
4
5
|
|
5
|
-
|
6
|
+
###################################################################
|
7
|
+
|
8
|
+
# @!macro [new] semaphore_method_initialize
|
6
9
|
#
|
7
|
-
#
|
8
|
-
# permits. Each {#acquire} blocks if necessary until a permit is
|
9
|
-
# available, and then takes it. Each {#release} adds a permit, potentially
|
10
|
-
# releasing a blocking acquirer.
|
11
|
-
# However, no actual permit objects are used; the Semaphore just keeps a
|
12
|
-
# count of the number available and acts accordingly.
|
10
|
+
# Create a new `Semaphore` with the initial `count`.
|
13
11
|
#
|
14
|
-
#
|
12
|
+
# @param [Fixnum] count the initial count
|
15
13
|
#
|
16
|
-
#
|
17
|
-
class MutexSemaphore < Synchronization::Object
|
18
|
-
|
19
|
-
# @!macro [attach] semaphore_method_initialize
|
20
|
-
#
|
21
|
-
# Create a new `Semaphore` with the initial `count`.
|
22
|
-
#
|
23
|
-
# @param [Fixnum] count the initial count
|
24
|
-
#
|
25
|
-
# @raise [ArgumentError] if `count` is not an integer or is less than zero
|
26
|
-
def initialize(count)
|
27
|
-
unless count.is_a?(Fixnum) && count >= 0
|
28
|
-
fail ArgumentError, 'count must be an non-negative integer'
|
29
|
-
end
|
30
|
-
super()
|
31
|
-
synchronize { ns_initialize count }
|
32
|
-
end
|
33
|
-
|
34
|
-
# @!macro [attach] semaphore_method_acquire
|
35
|
-
#
|
36
|
-
# Acquires the given number of permits from this semaphore,
|
37
|
-
# blocking until all are available.
|
38
|
-
#
|
39
|
-
# @param [Fixnum] permits Number of permits to acquire
|
40
|
-
#
|
41
|
-
# @raise [ArgumentError] if `permits` is not an integer or is less than
|
42
|
-
# one
|
43
|
-
#
|
44
|
-
# @return [Nil]
|
45
|
-
def acquire(permits = 1)
|
46
|
-
unless permits.is_a?(Fixnum) && permits > 0
|
47
|
-
fail ArgumentError, 'permits must be an integer greater than zero'
|
48
|
-
end
|
49
|
-
synchronize do
|
50
|
-
try_acquire_timed(permits, nil)
|
51
|
-
nil
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
# @!macro [attach] semaphore_method_available_permits
|
56
|
-
#
|
57
|
-
# Returns the current number of permits available in this semaphore.
|
58
|
-
#
|
59
|
-
# @return [Integer]
|
60
|
-
def available_permits
|
61
|
-
synchronize { @free }
|
62
|
-
end
|
63
|
-
|
64
|
-
# @!macro [attach] semaphore_method_drain_permits
|
65
|
-
#
|
66
|
-
# Acquires and returns all permits that are immediately available.
|
67
|
-
#
|
68
|
-
# @return [Integer]
|
69
|
-
def drain_permits
|
70
|
-
synchronize do
|
71
|
-
@free.tap { |_| @free = 0 }
|
72
|
-
end
|
73
|
-
end
|
14
|
+
# @raise [ArgumentError] if `count` is not an integer or is less than zero
|
74
15
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
# @raise [ArgumentError] if `permits` is not an integer or is less than
|
87
|
-
# one
|
88
|
-
#
|
89
|
-
# @return [Boolean] `false` if no permits are available, `true` when
|
90
|
-
# acquired a permit
|
91
|
-
def try_acquire(permits = 1, timeout = nil)
|
92
|
-
unless permits.is_a?(Fixnum) && permits > 0
|
93
|
-
fail ArgumentError, 'permits must be an integer greater than zero'
|
94
|
-
end
|
95
|
-
synchronize do
|
96
|
-
if timeout.nil?
|
97
|
-
try_acquire_now(permits)
|
98
|
-
else
|
99
|
-
try_acquire_timed(permits, timeout)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
16
|
+
# @!macro [new] semaphore_method_acquire
|
17
|
+
#
|
18
|
+
# Acquires the given number of permits from this semaphore,
|
19
|
+
# blocking until all are available.
|
20
|
+
#
|
21
|
+
# @param [Fixnum] permits Number of permits to acquire
|
22
|
+
#
|
23
|
+
# @raise [ArgumentError] if `permits` is not an integer or is less than
|
24
|
+
# one
|
25
|
+
#
|
26
|
+
# @return [nil]
|
103
27
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
#
|
110
|
-
# @raise [ArgumentError] if `permits` is not a number or is less than one
|
111
|
-
#
|
112
|
-
# @return [Nil]
|
113
|
-
def release(permits = 1)
|
114
|
-
unless permits.is_a?(Fixnum) && permits > 0
|
115
|
-
fail ArgumentError, 'permits must be an integer greater than zero'
|
116
|
-
end
|
117
|
-
synchronize do
|
118
|
-
@free += permits
|
119
|
-
permits.times { ns_signal }
|
120
|
-
end
|
121
|
-
nil
|
122
|
-
end
|
28
|
+
# @!macro [new] semaphore_method_available_permits
|
29
|
+
#
|
30
|
+
# Returns the current number of permits available in this semaphore.
|
31
|
+
#
|
32
|
+
# @return [Integer]
|
123
33
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
#
|
130
|
-
# @param [Fixnum] reduction Number of permits to remove.
|
131
|
-
#
|
132
|
-
# @raise [ArgumentError] if `reduction` is not an integer or is negative
|
133
|
-
#
|
134
|
-
# @raise [ArgumentError] if `@free` - `@reduction` is less than zero
|
135
|
-
#
|
136
|
-
# @return [Nil]
|
137
|
-
def reduce_permits(reduction)
|
138
|
-
unless reduction.is_a?(Fixnum) && reduction >= 0
|
139
|
-
fail ArgumentError, 'reduction must be an non-negative integer'
|
140
|
-
end
|
141
|
-
synchronize { @free -= reduction }
|
142
|
-
nil
|
143
|
-
end
|
34
|
+
# @!macro [new] semaphore_method_drain_permits
|
35
|
+
#
|
36
|
+
# Acquires and returns all permits that are immediately available.
|
37
|
+
#
|
38
|
+
# @return [Integer]
|
144
39
|
|
145
|
-
|
40
|
+
# @!macro [new] semaphore_method_try_acquire
|
41
|
+
#
|
42
|
+
# Acquires the given number of permits from this semaphore,
|
43
|
+
# only if all are available at the time of invocation or within
|
44
|
+
# `timeout` interval
|
45
|
+
#
|
46
|
+
# @param [Fixnum] permits the number of permits to acquire
|
47
|
+
#
|
48
|
+
# @param [Fixnum] timeout the number of seconds to wait for the counter
|
49
|
+
# or `nil` to return immediately
|
50
|
+
#
|
51
|
+
# @raise [ArgumentError] if `permits` is not an integer or is less than
|
52
|
+
# one
|
53
|
+
#
|
54
|
+
# @return [Boolean] `false` if no permits are available, `true` when
|
55
|
+
# acquired a permit
|
146
56
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
57
|
+
# @!macro [new] semaphore_method_release
|
58
|
+
#
|
59
|
+
# Releases the given number of permits, returning them to the semaphore.
|
60
|
+
#
|
61
|
+
# @param [Fixnum] permits Number of permits to return to the semaphore.
|
62
|
+
#
|
63
|
+
# @raise [ArgumentError] if `permits` is not a number or is less than one
|
64
|
+
#
|
65
|
+
# @return [nil]
|
151
66
|
|
152
|
-
|
67
|
+
###################################################################
|
153
68
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
69
|
+
# @!macro [new] semaphore_public_api
|
70
|
+
#
|
71
|
+
# @!method initialize(count)
|
72
|
+
# @!macro semaphore_method_initialize
|
73
|
+
#
|
74
|
+
# @!method acquire(permits = 1)
|
75
|
+
# @!macro semaphore_method_acquire
|
76
|
+
#
|
77
|
+
# @!method available_permits
|
78
|
+
# @!macro semaphore_method_available_permits
|
79
|
+
#
|
80
|
+
# @!method drain_permits
|
81
|
+
# @!macro semaphore_method_drain_permits
|
82
|
+
#
|
83
|
+
# @!method try_acquire(permits = 1, timeout = nil)
|
84
|
+
# @!macro semaphore_method_try_acquire
|
85
|
+
#
|
86
|
+
# @!method release(permits = 1)
|
87
|
+
# @!macro semaphore_method_release
|
163
88
|
|
164
|
-
|
165
|
-
def try_acquire_timed(permits, timeout)
|
166
|
-
ns_wait_until(timeout) { try_acquire_now(permits) }
|
167
|
-
end
|
168
|
-
end
|
89
|
+
###################################################################
|
169
90
|
|
170
91
|
# @!visibility private
|
171
92
|
# @!macro internal_implementation_note
|
172
93
|
SemaphoreImplementation = case
|
173
|
-
when
|
94
|
+
when defined?(JavaSemaphore)
|
174
95
|
JavaSemaphore
|
175
96
|
else
|
176
97
|
MutexSemaphore
|
177
98
|
end
|
178
99
|
private_constant :SemaphoreImplementation
|
179
100
|
|
180
|
-
# @!macro semaphore
|
101
|
+
# @!macro [attach] semaphore
|
181
102
|
#
|
182
|
-
#
|
103
|
+
# A counting semaphore. Conceptually, a semaphore maintains a set of
|
104
|
+
# permits. Each {#acquire} blocks if necessary until a permit is
|
105
|
+
# available, and then takes it. Each {#release} adds a permit, potentially
|
106
|
+
# releasing a blocking acquirer.
|
107
|
+
# However, no actual permit objects are used; the Semaphore just keeps a
|
108
|
+
# count of the number available and acts accordingly.
|
109
|
+
#
|
110
|
+
# @!macro semaphore_public_api
|
183
111
|
class Semaphore < SemaphoreImplementation
|
184
|
-
|
185
|
-
# @!method initialize(count)
|
186
|
-
# @!macro semaphore_method_initialize
|
187
|
-
|
188
|
-
# @!method acquire(permits = 1)
|
189
|
-
# @!macro semaphore_method_acquire
|
190
|
-
|
191
|
-
# @!method available_permits
|
192
|
-
# @!macro semaphore_method_available_permits
|
193
|
-
|
194
|
-
# @!method drain_permits
|
195
|
-
# @!macro semaphore_method_drain_permits
|
196
|
-
|
197
|
-
# @!method try_acquire(permits = 1, timeout = nil)
|
198
|
-
# @!macro semaphore_method_try_acquire
|
199
|
-
|
200
|
-
# @!method release(permits = 1)
|
201
|
-
# @!macro semaphore_method_release
|
202
|
-
|
203
|
-
# @!method reduce_permits(reduction)
|
204
|
-
# @!macro semaphore_method_reduce_permits
|
205
|
-
|
206
112
|
end
|
207
113
|
end
|