concurrent-ruby 1.0.5 → 1.1.6
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 +5 -5
- data/CHANGELOG.md +115 -0
- data/Gemfile +42 -0
- data/{LICENSE.txt → LICENSE.md} +2 -0
- data/README.md +242 -105
- data/Rakefile +332 -0
- data/ext/concurrent-ruby/ConcurrentRubyService.java +17 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/AtomicReferenceLibrary.java +175 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JRubyMapBackendLibrary.java +248 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicBooleanLibrary.java +93 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java +113 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java +159 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +307 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMap.java +31 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMapV8.java +3863 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/LongAdder.java +203 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/Striped64.java +342 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/ConcurrentHashMapV8.java +3800 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/LongAdder.java +204 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/Striped64.java +291 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166y/ThreadLocalRandom.java +199 -0
- data/lib/concurrent-ruby/concurrent-ruby.rb +1 -0
- data/lib/{concurrent.rb → concurrent-ruby/concurrent.rb} +24 -20
- data/lib/{concurrent → concurrent-ruby/concurrent}/agent.rb +7 -7
- data/lib/concurrent-ruby/concurrent/array.rb +66 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/async.rb +18 -4
- data/lib/{concurrent → concurrent-ruby/concurrent}/atom.rb +10 -10
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/abstract_thread_local_var.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_boolean.rb +26 -22
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_fixnum.rb +27 -23
- data/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb +164 -0
- data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +204 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/count_down_latch.rb +7 -7
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/cyclic_barrier.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/event.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/java_count_down_latch.rb +9 -6
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/java_thread_local_var.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_atomic_boolean.rb +2 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_atomic_fixnum.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_count_down_latch.rb +1 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_semaphore.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/read_write_lock.rb +2 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/reentrant_read_write_lock.rb +3 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/ruby_thread_local_var.rb +43 -33
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/semaphore.rb +8 -8
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/thread_local_var.rb +8 -8
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic_reference/mutex_atomic.rb +3 -8
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic_reference/numeric_cas_wrapper.rb +1 -1
- data/lib/concurrent-ruby/concurrent/atomics.rb +10 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/copy_on_notify_observer_set.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/copy_on_write_observer_set.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/java_non_concurrent_priority_queue.rb +0 -0
- data/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb +158 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/atomic_reference_map_backend.rb +3 -3
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/mri_map_backend.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/non_concurrent_map_backend.rb +1 -2
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/synchronized_map_backend.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/non_concurrent_priority_queue.rb +30 -30
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/ruby_non_concurrent_priority_queue.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/concern/deprecation.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/concern/dereferenceable.rb +3 -3
- data/lib/{concurrent → concurrent-ruby/concurrent}/concern/logging.rb +6 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/concern/obligation.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/concern/observable.rb +7 -7
- data/lib/concurrent-ruby/concurrent/concurrent_ruby.jar +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/configuration.rb +15 -15
- data/lib/{concurrent → concurrent-ruby/concurrent}/constants.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/dataflow.rb +2 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/delay.rb +9 -7
- data/lib/{concurrent → concurrent-ruby/concurrent}/errors.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/exchanger.rb +21 -25
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/abstract_executor_service.rb +19 -25
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/cached_thread_pool.rb +5 -5
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/executor_service.rb +17 -17
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/fixed_thread_pool.rb +27 -30
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/immediate_executor.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/indirect_immediate_executor.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_executor_service.rb +19 -16
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_single_thread_executor.rb +4 -3
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_thread_pool_executor.rb +12 -8
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_executor_service.rb +0 -2
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_single_thread_executor.rb +0 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_thread_pool_executor.rb +9 -4
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/safe_task_executor.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serial_executor_service.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serialized_execution.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serialized_execution_delegator.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/simple_executor_service.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/single_thread_executor.rb +3 -2
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/thread_pool_executor.rb +6 -6
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/timer_set.rb +14 -17
- data/lib/{concurrent → concurrent-ruby/concurrent}/executors.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/future.rb +4 -1
- data/lib/concurrent-ruby/concurrent/hash.rb +59 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/immutable_struct.rb +8 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/ivar.rb +5 -6
- data/lib/concurrent-ruby/concurrent/map.rb +337 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/maybe.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/mutable_struct.rb +25 -14
- data/lib/{concurrent → concurrent-ruby/concurrent}/mvar.rb +2 -2
- data/lib/{concurrent → concurrent-ruby/concurrent}/options.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/promise.rb +53 -21
- data/lib/concurrent-ruby/concurrent/promises.rb +2167 -0
- data/lib/concurrent-ruby/concurrent/re_include.rb +58 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/scheduled_task.rb +0 -0
- data/lib/concurrent-ruby/concurrent/set.rb +66 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/settable_struct.rb +11 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization.rb +4 -5
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_lockable_object.rb +5 -5
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_object.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_struct.rb +18 -4
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/condition.rb +2 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/jruby_lockable_object.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/jruby_object.rb +1 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/lock.rb +2 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/lockable_object.rb +6 -6
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/mri_object.rb +1 -0
- data/lib/{concurrent/synchronization/mri_lockable_object.rb → concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb} +19 -14
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/object.rb +53 -23
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/rbx_lockable_object.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/rbx_object.rb +1 -0
- data/lib/concurrent-ruby/concurrent/synchronization/truffleruby_object.rb +47 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/volatile.rb +11 -9
- data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/synchronized_delegator.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/adder.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/cheap_lockable.rb +0 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +63 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/power_of_two_tuple.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/striped64.rb +9 -4
- data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/volatile.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/xor_shift_random.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/timer_task.rb +5 -2
- data/lib/{concurrent → concurrent-ruby/concurrent}/tuple.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/tvar.rb +2 -2
- data/lib/{concurrent → concurrent-ruby/concurrent}/utility/engine.rb +4 -4
- data/lib/{concurrent → concurrent-ruby/concurrent}/utility/monotonic_time.rb +3 -3
- data/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb +79 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/utility/native_integer.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/utility/processor_counter.rb +5 -2
- data/lib/concurrent-ruby/concurrent/version.rb +3 -0
- metadata +146 -131
- data/lib/concurrent/array.rb +0 -39
- data/lib/concurrent/atomic/atomic_reference.rb +0 -51
- data/lib/concurrent/atomic_reference/concurrent_update_error.rb +0 -8
- data/lib/concurrent/atomic_reference/direct_update.rb +0 -81
- data/lib/concurrent/atomic_reference/jruby+truffle.rb +0 -2
- data/lib/concurrent/atomic_reference/jruby.rb +0 -16
- data/lib/concurrent/atomic_reference/rbx.rb +0 -22
- data/lib/concurrent/atomic_reference/ruby.rb +0 -32
- data/lib/concurrent/atomics.rb +0 -53
- data/lib/concurrent/edge.rb +0 -26
- data/lib/concurrent/hash.rb +0 -36
- data/lib/concurrent/lazy_register.rb +0 -81
- data/lib/concurrent/map.rb +0 -240
- data/lib/concurrent/synchronization/truffle_lockable_object.rb +0 -9
- data/lib/concurrent/synchronization/truffle_object.rb +0 -31
- data/lib/concurrent/thread_safe/util/array_hash_rbx.rb +0 -30
- data/lib/concurrent/utility/at_exit.rb +0 -97
- data/lib/concurrent/utility/native_extension_loader.rb +0 -73
- data/lib/concurrent/version.rb +0 -4
@@ -0,0 +1,204 @@
|
|
1
|
+
require 'concurrent/synchronization'
|
2
|
+
require 'concurrent/utility/engine'
|
3
|
+
require 'concurrent/atomic_reference/numeric_cas_wrapper'
|
4
|
+
|
5
|
+
# Shim for TruffleRuby::AtomicReference
|
6
|
+
if Concurrent.on_truffleruby? && !defined?(TruffleRuby::AtomicReference)
|
7
|
+
# @!visibility private
|
8
|
+
module TruffleRuby
|
9
|
+
AtomicReference = Truffle::AtomicReference
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module Concurrent
|
14
|
+
|
15
|
+
# Define update methods that use direct paths
|
16
|
+
#
|
17
|
+
# @!visibility private
|
18
|
+
# @!macro internal_implementation_note
|
19
|
+
module AtomicDirectUpdate
|
20
|
+
|
21
|
+
# @!macro atomic_reference_method_update
|
22
|
+
#
|
23
|
+
# Pass the current value to the given block, replacing it
|
24
|
+
# with the block's result. May retry if the value changes
|
25
|
+
# during the block's execution.
|
26
|
+
#
|
27
|
+
# @yield [Object] Calculate a new value for the atomic reference using
|
28
|
+
# given (old) value
|
29
|
+
# @yieldparam [Object] old_value the starting value of the atomic reference
|
30
|
+
# @return [Object] the new value
|
31
|
+
def update
|
32
|
+
true until compare_and_set(old_value = get, new_value = yield(old_value))
|
33
|
+
new_value
|
34
|
+
end
|
35
|
+
|
36
|
+
# @!macro atomic_reference_method_try_update
|
37
|
+
#
|
38
|
+
# Pass the current value to the given block, replacing it
|
39
|
+
# with the block's result. Return nil if the update fails.
|
40
|
+
#
|
41
|
+
# @yield [Object] Calculate a new value for the atomic reference using
|
42
|
+
# given (old) value
|
43
|
+
# @yieldparam [Object] old_value the starting value of the atomic reference
|
44
|
+
# @note This method was altered to avoid raising an exception by default.
|
45
|
+
# Instead, this method now returns `nil` in case of failure. For more info,
|
46
|
+
# please see: https://github.com/ruby-concurrency/concurrent-ruby/pull/336
|
47
|
+
# @return [Object] the new value, or nil if update failed
|
48
|
+
def try_update
|
49
|
+
old_value = get
|
50
|
+
new_value = yield old_value
|
51
|
+
|
52
|
+
return unless compare_and_set old_value, new_value
|
53
|
+
|
54
|
+
new_value
|
55
|
+
end
|
56
|
+
|
57
|
+
# @!macro atomic_reference_method_try_update!
|
58
|
+
#
|
59
|
+
# Pass the current value to the given block, replacing it
|
60
|
+
# with the block's result. Raise an exception if the update
|
61
|
+
# fails.
|
62
|
+
#
|
63
|
+
# @yield [Object] Calculate a new value for the atomic reference using
|
64
|
+
# given (old) value
|
65
|
+
# @yieldparam [Object] old_value the starting value of the atomic reference
|
66
|
+
# @note This behavior mimics the behavior of the original
|
67
|
+
# `AtomicReference#try_update` API. The reason this was changed was to
|
68
|
+
# avoid raising exceptions (which are inherently slow) by default. For more
|
69
|
+
# info: https://github.com/ruby-concurrency/concurrent-ruby/pull/336
|
70
|
+
# @return [Object] the new value
|
71
|
+
# @raise [Concurrent::ConcurrentUpdateError] if the update fails
|
72
|
+
def try_update!
|
73
|
+
old_value = get
|
74
|
+
new_value = yield old_value
|
75
|
+
unless compare_and_set(old_value, new_value)
|
76
|
+
if $VERBOSE
|
77
|
+
raise ConcurrentUpdateError, "Update failed"
|
78
|
+
else
|
79
|
+
raise ConcurrentUpdateError, "Update failed", ConcurrentUpdateError::CONC_UP_ERR_BACKTRACE
|
80
|
+
end
|
81
|
+
end
|
82
|
+
new_value
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
require 'concurrent/atomic_reference/mutex_atomic'
|
87
|
+
|
88
|
+
# @!macro atomic_reference
|
89
|
+
#
|
90
|
+
# An object reference that may be updated atomically. All read and write
|
91
|
+
# operations have java volatile semantic.
|
92
|
+
#
|
93
|
+
# @!macro thread_safe_variable_comparison
|
94
|
+
#
|
95
|
+
# @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicReference.html
|
96
|
+
# @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/package-summary.html
|
97
|
+
#
|
98
|
+
# @!method initialize(value = nil)
|
99
|
+
# @!macro atomic_reference_method_initialize
|
100
|
+
# @param [Object] value The initial value.
|
101
|
+
#
|
102
|
+
# @!method get
|
103
|
+
# @!macro atomic_reference_method_get
|
104
|
+
# Gets the current value.
|
105
|
+
# @return [Object] the current value
|
106
|
+
#
|
107
|
+
# @!method set(new_value)
|
108
|
+
# @!macro atomic_reference_method_set
|
109
|
+
# Sets to the given value.
|
110
|
+
# @param [Object] new_value the new value
|
111
|
+
# @return [Object] the new value
|
112
|
+
#
|
113
|
+
# @!method get_and_set(new_value)
|
114
|
+
# @!macro atomic_reference_method_get_and_set
|
115
|
+
# Atomically sets to the given value and returns the old value.
|
116
|
+
# @param [Object] new_value the new value
|
117
|
+
# @return [Object] the old value
|
118
|
+
#
|
119
|
+
# @!method compare_and_set(old_value, new_value)
|
120
|
+
# @!macro atomic_reference_method_compare_and_set
|
121
|
+
#
|
122
|
+
# Atomically sets the value to the given updated value if
|
123
|
+
# the current value == the expected value.
|
124
|
+
#
|
125
|
+
# @param [Object] old_value the expected value
|
126
|
+
# @param [Object] new_value the new value
|
127
|
+
#
|
128
|
+
# @return [Boolean] `true` if successful. A `false` return indicates
|
129
|
+
# that the actual value was not equal to the expected value.
|
130
|
+
#
|
131
|
+
# @!method update
|
132
|
+
# @!macro atomic_reference_method_update
|
133
|
+
#
|
134
|
+
# @!method try_update
|
135
|
+
# @!macro atomic_reference_method_try_update
|
136
|
+
#
|
137
|
+
# @!method try_update!
|
138
|
+
# @!macro atomic_reference_method_try_update!
|
139
|
+
|
140
|
+
|
141
|
+
# @!macro internal_implementation_note
|
142
|
+
class ConcurrentUpdateError < ThreadError
|
143
|
+
# frozen pre-allocated backtrace to speed ConcurrentUpdateError
|
144
|
+
CONC_UP_ERR_BACKTRACE = ['backtrace elided; set verbose to enable'].freeze
|
145
|
+
end
|
146
|
+
|
147
|
+
# @!macro internal_implementation_note
|
148
|
+
AtomicReferenceImplementation = case
|
149
|
+
when Concurrent.on_cruby? && Concurrent.c_extensions_loaded?
|
150
|
+
# @!visibility private
|
151
|
+
# @!macro internal_implementation_note
|
152
|
+
class CAtomicReference
|
153
|
+
include AtomicDirectUpdate
|
154
|
+
include AtomicNumericCompareAndSetWrapper
|
155
|
+
alias_method :compare_and_swap, :compare_and_set
|
156
|
+
end
|
157
|
+
CAtomicReference
|
158
|
+
when Concurrent.on_jruby?
|
159
|
+
# @!visibility private
|
160
|
+
# @!macro internal_implementation_note
|
161
|
+
class JavaAtomicReference
|
162
|
+
include AtomicDirectUpdate
|
163
|
+
end
|
164
|
+
JavaAtomicReference
|
165
|
+
when Concurrent.on_truffleruby?
|
166
|
+
class TruffleRubyAtomicReference < TruffleRuby::AtomicReference
|
167
|
+
include AtomicDirectUpdate
|
168
|
+
alias_method :value, :get
|
169
|
+
alias_method :value=, :set
|
170
|
+
alias_method :compare_and_swap, :compare_and_set
|
171
|
+
alias_method :swap, :get_and_set
|
172
|
+
end
|
173
|
+
when Concurrent.on_rbx?
|
174
|
+
# @note Extends `Rubinius::AtomicReference` version adding aliases
|
175
|
+
# and numeric logic.
|
176
|
+
#
|
177
|
+
# @!visibility private
|
178
|
+
# @!macro internal_implementation_note
|
179
|
+
class RbxAtomicReference < Rubinius::AtomicReference
|
180
|
+
alias_method :_compare_and_set, :compare_and_set
|
181
|
+
include AtomicDirectUpdate
|
182
|
+
include AtomicNumericCompareAndSetWrapper
|
183
|
+
alias_method :value, :get
|
184
|
+
alias_method :value=, :set
|
185
|
+
alias_method :swap, :get_and_set
|
186
|
+
alias_method :compare_and_swap, :compare_and_set
|
187
|
+
end
|
188
|
+
RbxAtomicReference
|
189
|
+
else
|
190
|
+
MutexAtomicReference
|
191
|
+
end
|
192
|
+
private_constant :AtomicReferenceImplementation
|
193
|
+
|
194
|
+
# @!macro atomic_reference
|
195
|
+
class AtomicReference < AtomicReferenceImplementation
|
196
|
+
|
197
|
+
# @return [String] Short string representation.
|
198
|
+
def to_s
|
199
|
+
format '%s value:%s>', super[0..-2], get
|
200
|
+
end
|
201
|
+
|
202
|
+
alias_method :inspect, :to_s
|
203
|
+
end
|
204
|
+
end
|
@@ -1,12 +1,12 @@
|
|
1
|
+
require 'concurrent/utility/engine'
|
1
2
|
require 'concurrent/atomic/mutex_count_down_latch'
|
2
3
|
require 'concurrent/atomic/java_count_down_latch'
|
3
|
-
require 'concurrent/utility/engine'
|
4
4
|
|
5
5
|
module Concurrent
|
6
6
|
|
7
7
|
###################################################################
|
8
8
|
|
9
|
-
# @!macro
|
9
|
+
# @!macro count_down_latch_method_initialize
|
10
10
|
#
|
11
11
|
# Create a new `CountDownLatch` with the initial `count`.
|
12
12
|
#
|
@@ -14,7 +14,7 @@ module Concurrent
|
|
14
14
|
#
|
15
15
|
# @raise [ArgumentError] if `count` is not an integer or is less than zero
|
16
16
|
|
17
|
-
# @!macro
|
17
|
+
# @!macro count_down_latch_method_wait
|
18
18
|
#
|
19
19
|
# Block on the latch until the counter reaches zero or until `timeout` is reached.
|
20
20
|
#
|
@@ -22,12 +22,12 @@ module Concurrent
|
|
22
22
|
# to block indefinitely
|
23
23
|
# @return [Boolean] `true` if the `count` reaches zero else false on `timeout`
|
24
24
|
|
25
|
-
# @!macro
|
25
|
+
# @!macro count_down_latch_method_count_down
|
26
26
|
#
|
27
27
|
# Signal the latch to decrement the counter. Will signal all blocked threads when
|
28
28
|
# the `count` reaches zero.
|
29
29
|
|
30
|
-
# @!macro
|
30
|
+
# @!macro count_down_latch_method_count
|
31
31
|
#
|
32
32
|
# The current value of the counter.
|
33
33
|
#
|
@@ -35,7 +35,7 @@ module Concurrent
|
|
35
35
|
|
36
36
|
###################################################################
|
37
37
|
|
38
|
-
# @!macro
|
38
|
+
# @!macro count_down_latch_public_api
|
39
39
|
#
|
40
40
|
# @!method initialize(count = 1)
|
41
41
|
# @!macro count_down_latch_method_initialize
|
@@ -61,7 +61,7 @@ module Concurrent
|
|
61
61
|
end
|
62
62
|
private_constant :CountDownLatchImplementation
|
63
63
|
|
64
|
-
# @!macro
|
64
|
+
# @!macro count_down_latch
|
65
65
|
#
|
66
66
|
# A synchronization object that allows one thread to wait on multiple other threads.
|
67
67
|
# The thread that will wait creates a `CountDownLatch` and sets the initial value
|
@@ -23,7 +23,7 @@ module Concurrent
|
|
23
23
|
# # use main as well
|
24
24
|
# process.call 2
|
25
25
|
#
|
26
|
-
# # here we can be sure that all jobs are processed
|
26
|
+
# # here we can be sure that all jobs are processed
|
27
27
|
class CyclicBarrier < Synchronization::LockableObject
|
28
28
|
|
29
29
|
# @!visibility private
|
@@ -9,20 +9,23 @@ if Concurrent.on_jruby?
|
|
9
9
|
|
10
10
|
# @!macro count_down_latch_method_initialize
|
11
11
|
def initialize(count = 1)
|
12
|
-
|
13
|
-
|
14
|
-
end
|
12
|
+
Utility::NativeInteger.ensure_integer_and_bounds(count)
|
13
|
+
Utility::NativeInteger.ensure_positive(count)
|
15
14
|
@latch = java.util.concurrent.CountDownLatch.new(count)
|
16
15
|
end
|
17
16
|
|
18
17
|
# @!macro count_down_latch_method_wait
|
19
18
|
def wait(timeout = nil)
|
19
|
+
result = nil
|
20
20
|
if timeout.nil?
|
21
|
-
@latch.await
|
22
|
-
true
|
21
|
+
Synchronization::JRuby.sleep_interruptibly { @latch.await }
|
22
|
+
result = true
|
23
23
|
else
|
24
|
-
|
24
|
+
Synchronization::JRuby.sleep_interruptibly do
|
25
|
+
result = @latch.await(1000 * timeout, java.util.concurrent.TimeUnit::MILLISECONDS)
|
26
|
+
end
|
25
27
|
end
|
28
|
+
result
|
26
29
|
end
|
27
30
|
|
28
31
|
# @!macro count_down_latch_method_count_down
|
File without changes
|
File without changes
|
File without changes
|
@@ -193,7 +193,8 @@ module Concurrent
|
|
193
193
|
#
|
194
194
|
# @return [Boolean] true if the lock is successfully released
|
195
195
|
def release_write_lock
|
196
|
-
|
196
|
+
return true unless running_writer?
|
197
|
+
c = @Counter.update { |counter| counter - RUNNING_WRITER }
|
197
198
|
@ReadLock.broadcast
|
198
199
|
@WriteLock.signal if waiting_writers(c) > 0
|
199
200
|
true
|
@@ -21,7 +21,9 @@ module Concurrent
|
|
21
21
|
# also acquire a read lock OR a write lock more than once. Only when the read (or
|
22
22
|
# write) lock is released as many times as it was acquired, will the thread
|
23
23
|
# actually let it go, allowing other threads which might have been waiting
|
24
|
-
# to proceed.
|
24
|
+
# to proceed. Therefore the lock can be upgraded by first acquiring
|
25
|
+
# read lock and then write lock and that the lock can be downgraded by first
|
26
|
+
# having both read and write lock a releasing just the write lock.
|
25
27
|
#
|
26
28
|
# If both read and write locks are acquired by the same thread, it is not strictly
|
27
29
|
# necessary to release them in the same order they were acquired. In other words,
|
@@ -32,12 +32,38 @@ module Concurrent
|
|
32
32
|
FREE = []
|
33
33
|
LOCK = Mutex.new
|
34
34
|
ARRAYS = {} # used as a hash set
|
35
|
+
# noinspection RubyClassVariableUsageInspection
|
35
36
|
@@next = 0
|
36
|
-
|
37
|
+
QUEUE = Queue.new
|
38
|
+
THREAD = Thread.new do
|
39
|
+
while true
|
40
|
+
method, i = QUEUE.pop
|
41
|
+
case method
|
42
|
+
when :thread_local_finalizer
|
43
|
+
LOCK.synchronize do
|
44
|
+
FREE.push(i)
|
45
|
+
# The cost of GC'ing a TLV is linear in the number of threads using TLVs
|
46
|
+
# But that is natural! More threads means more storage is used per TLV
|
47
|
+
# So naturally more CPU time is required to free more storage
|
48
|
+
ARRAYS.each_value do |array|
|
49
|
+
array[i] = nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
when :thread_finalizer
|
53
|
+
LOCK.synchronize do
|
54
|
+
# The thread which used this thread-local array is now gone
|
55
|
+
# So don't hold onto a reference to the array (thus blocking GC)
|
56
|
+
ARRAYS.delete(i)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private_constant :FREE, :LOCK, :ARRAYS, :QUEUE, :THREAD
|
37
63
|
|
38
64
|
# @!macro thread_local_var_method_get
|
39
65
|
def value
|
40
|
-
if array = get_threadlocal_array
|
66
|
+
if (array = get_threadlocal_array)
|
41
67
|
value = array[@index]
|
42
68
|
if value.nil?
|
43
69
|
default
|
@@ -57,10 +83,10 @@ module Concurrent
|
|
57
83
|
# We could keep the thread-local arrays in a hash, keyed by Thread
|
58
84
|
# But why? That would require locking
|
59
85
|
# Using Ruby's built-in thread-local storage is faster
|
60
|
-
unless array = get_threadlocal_array(me)
|
86
|
+
unless (array = get_threadlocal_array(me))
|
61
87
|
array = set_threadlocal_array([], me)
|
62
88
|
LOCK.synchronize { ARRAYS[array.object_id] = array }
|
63
|
-
ObjectSpace.define_finalizer(me, self.class.thread_finalizer(array))
|
89
|
+
ObjectSpace.define_finalizer(me, self.class.thread_finalizer(array.object_id))
|
64
90
|
end
|
65
91
|
array[@index] = (value.nil? ? NULL : value)
|
66
92
|
value
|
@@ -69,6 +95,7 @@ module Concurrent
|
|
69
95
|
protected
|
70
96
|
|
71
97
|
# @!visibility private
|
98
|
+
# noinspection RubyClassVariableUsageInspection
|
72
99
|
def allocate_storage
|
73
100
|
@index = LOCK.synchronize do
|
74
101
|
FREE.pop || begin
|
@@ -77,37 +104,19 @@ module Concurrent
|
|
77
104
|
result
|
78
105
|
end
|
79
106
|
end
|
80
|
-
ObjectSpace.define_finalizer(self, self.class.
|
107
|
+
ObjectSpace.define_finalizer(self, self.class.thread_local_finalizer(@index))
|
81
108
|
end
|
82
109
|
|
83
110
|
# @!visibility private
|
84
|
-
def self.
|
85
|
-
|
86
|
-
|
87
|
-
LOCK.synchronize do
|
88
|
-
FREE.push(index)
|
89
|
-
# The cost of GC'ing a TLV is linear in the number of threads using TLVs
|
90
|
-
# But that is natural! More threads means more storage is used per TLV
|
91
|
-
# So naturally more CPU time is required to free more storage
|
92
|
-
ARRAYS.each_value do |array|
|
93
|
-
array[index] = nil
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
111
|
+
def self.thread_local_finalizer(index)
|
112
|
+
# avoid error: can't be called from trap context
|
113
|
+
proc { QUEUE.push [:thread_local_finalizer, index] }
|
98
114
|
end
|
99
115
|
|
100
116
|
# @!visibility private
|
101
|
-
def self.thread_finalizer(
|
102
|
-
|
103
|
-
|
104
|
-
LOCK.synchronize do
|
105
|
-
# The thread which used this thread-local array is now gone
|
106
|
-
# So don't hold onto a reference to the array (thus blocking GC)
|
107
|
-
ARRAYS.delete(array.object_id)
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
117
|
+
def self.thread_finalizer(id)
|
118
|
+
# avoid error: can't be called from trap context
|
119
|
+
proc { QUEUE.push [:thread_finalizer, id] }
|
111
120
|
end
|
112
121
|
|
113
122
|
private
|
@@ -136,21 +145,22 @@ module Concurrent
|
|
136
145
|
# This exists only for use in testing
|
137
146
|
# @!visibility private
|
138
147
|
def value_for(thread)
|
139
|
-
if array = get_threadlocal_array(thread)
|
148
|
+
if (array = get_threadlocal_array(thread))
|
140
149
|
value = array[@index]
|
141
150
|
if value.nil?
|
142
|
-
|
151
|
+
get_default
|
143
152
|
elsif value.equal?(NULL)
|
144
153
|
nil
|
145
154
|
else
|
146
155
|
value
|
147
156
|
end
|
148
157
|
else
|
149
|
-
|
158
|
+
get_default
|
150
159
|
end
|
151
160
|
end
|
152
161
|
|
153
|
-
|
162
|
+
# @!visibility private
|
163
|
+
def get_default
|
154
164
|
if @default_block
|
155
165
|
raise "Cannot use default_for with default block"
|
156
166
|
else
|