concurrent-ruby 1.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +478 -0
- data/Gemfile +41 -0
- data/LICENSE.md +23 -0
- data/README.md +381 -0
- data/Rakefile +327 -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.rb +1 -0
- data/lib/concurrent.rb +134 -0
- data/lib/concurrent/agent.rb +587 -0
- data/lib/concurrent/array.rb +66 -0
- data/lib/concurrent/async.rb +459 -0
- data/lib/concurrent/atom.rb +222 -0
- data/lib/concurrent/atomic/abstract_thread_local_var.rb +66 -0
- data/lib/concurrent/atomic/atomic_boolean.rb +126 -0
- data/lib/concurrent/atomic/atomic_fixnum.rb +143 -0
- data/lib/concurrent/atomic/atomic_markable_reference.rb +164 -0
- data/lib/concurrent/atomic/atomic_reference.rb +204 -0
- data/lib/concurrent/atomic/count_down_latch.rb +100 -0
- data/lib/concurrent/atomic/cyclic_barrier.rb +128 -0
- data/lib/concurrent/atomic/event.rb +109 -0
- data/lib/concurrent/atomic/java_count_down_latch.rb +42 -0
- data/lib/concurrent/atomic/java_thread_local_var.rb +37 -0
- data/lib/concurrent/atomic/mutex_atomic_boolean.rb +62 -0
- data/lib/concurrent/atomic/mutex_atomic_fixnum.rb +75 -0
- data/lib/concurrent/atomic/mutex_count_down_latch.rb +44 -0
- data/lib/concurrent/atomic/mutex_semaphore.rb +115 -0
- data/lib/concurrent/atomic/read_write_lock.rb +254 -0
- data/lib/concurrent/atomic/reentrant_read_write_lock.rb +379 -0
- data/lib/concurrent/atomic/ruby_thread_local_var.rb +161 -0
- data/lib/concurrent/atomic/semaphore.rb +145 -0
- data/lib/concurrent/atomic/thread_local_var.rb +104 -0
- data/lib/concurrent/atomic_reference/mutex_atomic.rb +56 -0
- data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +28 -0
- data/lib/concurrent/atomics.rb +10 -0
- data/lib/concurrent/collection/copy_on_notify_observer_set.rb +107 -0
- data/lib/concurrent/collection/copy_on_write_observer_set.rb +111 -0
- data/lib/concurrent/collection/java_non_concurrent_priority_queue.rb +84 -0
- data/lib/concurrent/collection/lock_free_stack.rb +158 -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 +140 -0
- data/lib/concurrent/collection/map/synchronized_map_backend.rb +82 -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/deprecation.rb +34 -0
- data/lib/concurrent/concern/dereferenceable.rb +73 -0
- data/lib/concurrent/concern/logging.rb +32 -0
- data/lib/concurrent/concern/obligation.rb +220 -0
- data/lib/concurrent/concern/observable.rb +110 -0
- data/lib/concurrent/concurrent_ruby.jar +0 -0
- data/lib/concurrent/configuration.rb +184 -0
- data/lib/concurrent/constants.rb +8 -0
- data/lib/concurrent/dataflow.rb +81 -0
- data/lib/concurrent/delay.rb +199 -0
- data/lib/concurrent/errors.rb +69 -0
- data/lib/concurrent/exchanger.rb +352 -0
- data/lib/concurrent/executor/abstract_executor_service.rb +134 -0
- data/lib/concurrent/executor/cached_thread_pool.rb +62 -0
- data/lib/concurrent/executor/executor_service.rb +185 -0
- data/lib/concurrent/executor/fixed_thread_pool.rb +206 -0
- data/lib/concurrent/executor/immediate_executor.rb +66 -0
- data/lib/concurrent/executor/indirect_immediate_executor.rb +44 -0
- data/lib/concurrent/executor/java_executor_service.rb +91 -0
- data/lib/concurrent/executor/java_single_thread_executor.rb +29 -0
- data/lib/concurrent/executor/java_thread_pool_executor.rb +123 -0
- data/lib/concurrent/executor/ruby_executor_service.rb +78 -0
- data/lib/concurrent/executor/ruby_single_thread_executor.rb +22 -0
- data/lib/concurrent/executor/ruby_thread_pool_executor.rb +362 -0
- data/lib/concurrent/executor/safe_task_executor.rb +35 -0
- data/lib/concurrent/executor/serial_executor_service.rb +34 -0
- data/lib/concurrent/executor/serialized_execution.rb +107 -0
- data/lib/concurrent/executor/serialized_execution_delegator.rb +28 -0
- data/lib/concurrent/executor/simple_executor_service.rb +100 -0
- data/lib/concurrent/executor/single_thread_executor.rb +56 -0
- data/lib/concurrent/executor/thread_pool_executor.rb +87 -0
- data/lib/concurrent/executor/timer_set.rb +173 -0
- data/lib/concurrent/executors.rb +20 -0
- data/lib/concurrent/future.rb +141 -0
- data/lib/concurrent/hash.rb +59 -0
- data/lib/concurrent/immutable_struct.rb +93 -0
- data/lib/concurrent/ivar.rb +207 -0
- data/lib/concurrent/map.rb +337 -0
- data/lib/concurrent/maybe.rb +229 -0
- data/lib/concurrent/mutable_struct.rb +229 -0
- data/lib/concurrent/mvar.rb +242 -0
- data/lib/concurrent/options.rb +42 -0
- data/lib/concurrent/promise.rb +579 -0
- data/lib/concurrent/promises.rb +2167 -0
- data/lib/concurrent/re_include.rb +58 -0
- data/lib/concurrent/scheduled_task.rb +318 -0
- data/lib/concurrent/set.rb +66 -0
- data/lib/concurrent/settable_struct.rb +129 -0
- data/lib/concurrent/synchronization.rb +30 -0
- data/lib/concurrent/synchronization/abstract_lockable_object.rb +98 -0
- data/lib/concurrent/synchronization/abstract_object.rb +24 -0
- data/lib/concurrent/synchronization/abstract_struct.rb +160 -0
- data/lib/concurrent/synchronization/condition.rb +60 -0
- data/lib/concurrent/synchronization/jruby_lockable_object.rb +13 -0
- data/lib/concurrent/synchronization/jruby_object.rb +45 -0
- data/lib/concurrent/synchronization/lock.rb +36 -0
- data/lib/concurrent/synchronization/lockable_object.rb +74 -0
- data/lib/concurrent/synchronization/mri_object.rb +44 -0
- data/lib/concurrent/synchronization/mutex_lockable_object.rb +76 -0
- data/lib/concurrent/synchronization/object.rb +183 -0
- data/lib/concurrent/synchronization/rbx_lockable_object.rb +65 -0
- data/lib/concurrent/synchronization/rbx_object.rb +49 -0
- data/lib/concurrent/synchronization/truffleruby_object.rb +47 -0
- data/lib/concurrent/synchronization/volatile.rb +36 -0
- data/lib/concurrent/thread_safe/synchronized_delegator.rb +50 -0
- data/lib/concurrent/thread_safe/util.rb +16 -0
- data/lib/concurrent/thread_safe/util/adder.rb +74 -0
- data/lib/concurrent/thread_safe/util/cheap_lockable.rb +118 -0
- data/lib/concurrent/thread_safe/util/data_structures.rb +63 -0
- data/lib/concurrent/thread_safe/util/power_of_two_tuple.rb +38 -0
- data/lib/concurrent/thread_safe/util/striped64.rb +246 -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 +334 -0
- data/lib/concurrent/tuple.rb +86 -0
- data/lib/concurrent/tvar.rb +258 -0
- data/lib/concurrent/utility/at_exit.rb +97 -0
- data/lib/concurrent/utility/engine.rb +56 -0
- data/lib/concurrent/utility/monotonic_time.rb +58 -0
- data/lib/concurrent/utility/native_extension_loader.rb +79 -0
- data/lib/concurrent/utility/native_integer.rb +53 -0
- data/lib/concurrent/utility/processor_counter.rb +158 -0
- data/lib/concurrent/version.rb +3 -0
- metadata +193 -0
@@ -0,0 +1,222 @@
|
|
1
|
+
require 'concurrent/atomic/atomic_reference'
|
2
|
+
require 'concurrent/collection/copy_on_notify_observer_set'
|
3
|
+
require 'concurrent/concern/observable'
|
4
|
+
require 'concurrent/synchronization'
|
5
|
+
|
6
|
+
# @!macro thread_safe_variable_comparison
|
7
|
+
#
|
8
|
+
# ## Thread-safe Variable Classes
|
9
|
+
#
|
10
|
+
# Each of the thread-safe variable classes is designed to solve a different
|
11
|
+
# problem. In general:
|
12
|
+
#
|
13
|
+
# * *{Concurrent::Agent}:* Shared, mutable variable providing independent,
|
14
|
+
# uncoordinated, *asynchronous* change of individual values. Best used when
|
15
|
+
# the value will undergo frequent, complex updates. Suitable when the result
|
16
|
+
# of an update does not need to be known immediately.
|
17
|
+
# * *{Concurrent::Atom}:* Shared, mutable variable providing independent,
|
18
|
+
# uncoordinated, *synchronous* change of individual values. Best used when
|
19
|
+
# the value will undergo frequent reads but only occasional, though complex,
|
20
|
+
# updates. Suitable when the result of an update must be known immediately.
|
21
|
+
# * *{Concurrent::AtomicReference}:* A simple object reference that can be
|
22
|
+
# atomically. Updates are synchronous but fast. Best used when updates a
|
23
|
+
# simple set operations. Not suitable when updates are complex.
|
24
|
+
# {Concurrent::AtomicBoolean} and {Concurrent::AtomicFixnum} are similar
|
25
|
+
# but optimized for the given data type.
|
26
|
+
# * *{Concurrent::Exchanger}:* Shared, stateless synchronization point. Used
|
27
|
+
# when two or more threads need to exchange data. The threads will pair then
|
28
|
+
# block on each other until the exchange is complete.
|
29
|
+
# * *{Concurrent::MVar}:* Shared synchronization point. Used when one thread
|
30
|
+
# must give a value to another, which must take the value. The threads will
|
31
|
+
# block on each other until the exchange is complete.
|
32
|
+
# * *{Concurrent::ThreadLocalVar}:* Shared, mutable, isolated variable which
|
33
|
+
# holds a different value for each thread which has access. Often used as
|
34
|
+
# an instance variable in objects which must maintain different state
|
35
|
+
# for different threads.
|
36
|
+
# * *{Concurrent::TVar}:* Shared, mutable variables which provide
|
37
|
+
# *coordinated*, *synchronous*, change of *many* stated. Used when multiple
|
38
|
+
# value must change together, in an all-or-nothing transaction.
|
39
|
+
|
40
|
+
|
41
|
+
module Concurrent
|
42
|
+
|
43
|
+
# Atoms provide a way to manage shared, synchronous, independent state.
|
44
|
+
#
|
45
|
+
# An atom is initialized with an initial value and an optional validation
|
46
|
+
# proc. At any time the value of the atom can be synchronously and safely
|
47
|
+
# changed. If a validator is given at construction then any new value
|
48
|
+
# will be checked against the validator and will be rejected if the
|
49
|
+
# validator returns false or raises an exception.
|
50
|
+
#
|
51
|
+
# There are two ways to change the value of an atom: {#compare_and_set} and
|
52
|
+
# {#swap}. The former will set the new value if and only if it validates and
|
53
|
+
# the current value matches the new value. The latter will atomically set the
|
54
|
+
# new value to the result of running the given block if and only if that
|
55
|
+
# value validates.
|
56
|
+
#
|
57
|
+
# ## Example
|
58
|
+
#
|
59
|
+
# ```
|
60
|
+
# def next_fibonacci(set = nil)
|
61
|
+
# return [0, 1] if set.nil?
|
62
|
+
# set + [set[-2..-1].reduce{|sum,x| sum + x }]
|
63
|
+
# end
|
64
|
+
#
|
65
|
+
# # create an atom with an initial value
|
66
|
+
# atom = Concurrent::Atom.new(next_fibonacci)
|
67
|
+
#
|
68
|
+
# # send a few update requests
|
69
|
+
# 5.times do
|
70
|
+
# atom.swap{|set| next_fibonacci(set) }
|
71
|
+
# end
|
72
|
+
#
|
73
|
+
# # get the current value
|
74
|
+
# atom.value #=> [0, 1, 1, 2, 3, 5, 8]
|
75
|
+
# ```
|
76
|
+
#
|
77
|
+
# ## Observation
|
78
|
+
#
|
79
|
+
# Atoms support observers through the {Concurrent::Observable} mixin module.
|
80
|
+
# Notification of observers occurs every time the value of the Atom changes.
|
81
|
+
# When notified the observer will receive three arguments: `time`, `old_value`,
|
82
|
+
# and `new_value`. The `time` argument is the time at which the value change
|
83
|
+
# occurred. The `old_value` is the value of the Atom when the change began
|
84
|
+
# The `new_value` is the value to which the Atom was set when the change
|
85
|
+
# completed. Note that `old_value` and `new_value` may be the same. This is
|
86
|
+
# not an error. It simply means that the change operation returned the same
|
87
|
+
# value.
|
88
|
+
#
|
89
|
+
# Unlike in Clojure, `Atom` cannot participate in {Concurrent::TVar} transactions.
|
90
|
+
#
|
91
|
+
# @!macro thread_safe_variable_comparison
|
92
|
+
#
|
93
|
+
# @see http://clojure.org/atoms Clojure Atoms
|
94
|
+
# @see http://clojure.org/state Values and Change - Clojure's approach to Identity and State
|
95
|
+
class Atom < Synchronization::Object
|
96
|
+
include Concern::Observable
|
97
|
+
|
98
|
+
safe_initialization!
|
99
|
+
attr_atomic(:value)
|
100
|
+
private :value=, :swap_value, :compare_and_set_value, :update_value
|
101
|
+
public :value
|
102
|
+
alias_method :deref, :value
|
103
|
+
|
104
|
+
# @!method value
|
105
|
+
# The current value of the atom.
|
106
|
+
#
|
107
|
+
# @return [Object] The current value.
|
108
|
+
|
109
|
+
# Create a new atom with the given initial value.
|
110
|
+
#
|
111
|
+
# @param [Object] value The initial value
|
112
|
+
# @param [Hash] opts The options used to configure the atom
|
113
|
+
# @option opts [Proc] :validator (nil) Optional proc used to validate new
|
114
|
+
# values. It must accept one and only one argument which will be the
|
115
|
+
# intended new value. The validator will return true if the new value
|
116
|
+
# is acceptable else return false (preferrably) or raise an exception.
|
117
|
+
#
|
118
|
+
# @!macro deref_options
|
119
|
+
#
|
120
|
+
# @raise [ArgumentError] if the validator is not a `Proc` (when given)
|
121
|
+
def initialize(value, opts = {})
|
122
|
+
super()
|
123
|
+
@Validator = opts.fetch(:validator, -> v { true })
|
124
|
+
self.observers = Collection::CopyOnNotifyObserverSet.new
|
125
|
+
self.value = value
|
126
|
+
end
|
127
|
+
|
128
|
+
# Atomically swaps the value of atom using the given block. The current
|
129
|
+
# value will be passed to the block, as will any arguments passed as
|
130
|
+
# arguments to the function. The new value will be validated against the
|
131
|
+
# (optional) validator proc given at construction. If validation fails the
|
132
|
+
# value will not be changed.
|
133
|
+
#
|
134
|
+
# Internally, {#swap} reads the current value, applies the block to it, and
|
135
|
+
# attempts to compare-and-set it in. Since another thread may have changed
|
136
|
+
# the value in the intervening time, it may have to retry, and does so in a
|
137
|
+
# spin loop. The net effect is that the value will always be the result of
|
138
|
+
# the application of the supplied block to a current value, atomically.
|
139
|
+
# However, because the block might be called multiple times, it must be free
|
140
|
+
# of side effects.
|
141
|
+
#
|
142
|
+
# @note The given block may be called multiple times, and thus should be free
|
143
|
+
# of side effects.
|
144
|
+
#
|
145
|
+
# @param [Object] args Zero or more arguments passed to the block.
|
146
|
+
#
|
147
|
+
# @yield [value, args] Calculates a new value for the atom based on the
|
148
|
+
# current value and any supplied arguments.
|
149
|
+
# @yieldparam value [Object] The current value of the atom.
|
150
|
+
# @yieldparam args [Object] All arguments passed to the function, in order.
|
151
|
+
# @yieldreturn [Object] The intended new value of the atom.
|
152
|
+
#
|
153
|
+
# @return [Object] The final value of the atom after all operations and
|
154
|
+
# validations are complete.
|
155
|
+
#
|
156
|
+
# @raise [ArgumentError] When no block is given.
|
157
|
+
def swap(*args)
|
158
|
+
raise ArgumentError.new('no block given') unless block_given?
|
159
|
+
|
160
|
+
loop do
|
161
|
+
old_value = value
|
162
|
+
new_value = yield(old_value, *args)
|
163
|
+
begin
|
164
|
+
break old_value unless valid?(new_value)
|
165
|
+
break new_value if compare_and_set(old_value, new_value)
|
166
|
+
rescue
|
167
|
+
break old_value
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# Atomically sets the value of atom to the new value if and only if the
|
173
|
+
# current value of the atom is identical to the old value and the new
|
174
|
+
# value successfully validates against the (optional) validator given
|
175
|
+
# at construction.
|
176
|
+
#
|
177
|
+
# @param [Object] old_value The expected current value.
|
178
|
+
# @param [Object] new_value The intended new value.
|
179
|
+
#
|
180
|
+
# @return [Boolean] True if the value is changed else false.
|
181
|
+
def compare_and_set(old_value, new_value)
|
182
|
+
if valid?(new_value) && compare_and_set_value(old_value, new_value)
|
183
|
+
observers.notify_observers(Time.now, old_value, new_value)
|
184
|
+
true
|
185
|
+
else
|
186
|
+
false
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
# Atomically sets the value of atom to the new value without regard for the
|
191
|
+
# current value so long as the new value successfully validates against the
|
192
|
+
# (optional) validator given at construction.
|
193
|
+
#
|
194
|
+
# @param [Object] new_value The intended new value.
|
195
|
+
#
|
196
|
+
# @return [Object] The final value of the atom after all operations and
|
197
|
+
# validations are complete.
|
198
|
+
def reset(new_value)
|
199
|
+
old_value = value
|
200
|
+
if valid?(new_value)
|
201
|
+
self.value = new_value
|
202
|
+
observers.notify_observers(Time.now, old_value, new_value)
|
203
|
+
new_value
|
204
|
+
else
|
205
|
+
old_value
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
private
|
210
|
+
|
211
|
+
# Is the new value valid?
|
212
|
+
#
|
213
|
+
# @param [Object] new_value The intended new value.
|
214
|
+
# @return [Boolean] false if the validator function returns false or raises
|
215
|
+
# an exception else true
|
216
|
+
def valid?(new_value)
|
217
|
+
@Validator.call(new_value)
|
218
|
+
rescue
|
219
|
+
false
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'concurrent/constants'
|
2
|
+
|
3
|
+
module Concurrent
|
4
|
+
|
5
|
+
# @!macro thread_local_var
|
6
|
+
# @!macro internal_implementation_note
|
7
|
+
# @!visibility private
|
8
|
+
class AbstractThreadLocalVar
|
9
|
+
|
10
|
+
# @!macro thread_local_var_method_initialize
|
11
|
+
def initialize(default = nil, &default_block)
|
12
|
+
if default && block_given?
|
13
|
+
raise ArgumentError, "Cannot use both value and block as default value"
|
14
|
+
end
|
15
|
+
|
16
|
+
if block_given?
|
17
|
+
@default_block = default_block
|
18
|
+
@default = nil
|
19
|
+
else
|
20
|
+
@default_block = nil
|
21
|
+
@default = default
|
22
|
+
end
|
23
|
+
|
24
|
+
allocate_storage
|
25
|
+
end
|
26
|
+
|
27
|
+
# @!macro thread_local_var_method_get
|
28
|
+
def value
|
29
|
+
raise NotImplementedError
|
30
|
+
end
|
31
|
+
|
32
|
+
# @!macro thread_local_var_method_set
|
33
|
+
def value=(value)
|
34
|
+
raise NotImplementedError
|
35
|
+
end
|
36
|
+
|
37
|
+
# @!macro thread_local_var_method_bind
|
38
|
+
def bind(value, &block)
|
39
|
+
if block_given?
|
40
|
+
old_value = self.value
|
41
|
+
begin
|
42
|
+
self.value = value
|
43
|
+
yield
|
44
|
+
ensure
|
45
|
+
self.value = old_value
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
protected
|
51
|
+
|
52
|
+
# @!visibility private
|
53
|
+
def allocate_storage
|
54
|
+
raise NotImplementedError
|
55
|
+
end
|
56
|
+
|
57
|
+
# @!visibility private
|
58
|
+
def default
|
59
|
+
if @default_block
|
60
|
+
self.value = @default_block.call
|
61
|
+
else
|
62
|
+
@default
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'concurrent/atomic/mutex_atomic_boolean'
|
2
|
+
require 'concurrent/synchronization'
|
3
|
+
|
4
|
+
module Concurrent
|
5
|
+
|
6
|
+
###################################################################
|
7
|
+
|
8
|
+
# @!macro atomic_boolean_method_initialize
|
9
|
+
#
|
10
|
+
# Creates a new `AtomicBoolean` with the given initial value.
|
11
|
+
#
|
12
|
+
# @param [Boolean] initial the initial value
|
13
|
+
|
14
|
+
# @!macro atomic_boolean_method_value_get
|
15
|
+
#
|
16
|
+
# Retrieves the current `Boolean` value.
|
17
|
+
#
|
18
|
+
# @return [Boolean] the current value
|
19
|
+
|
20
|
+
# @!macro atomic_boolean_method_value_set
|
21
|
+
#
|
22
|
+
# Explicitly sets the value.
|
23
|
+
#
|
24
|
+
# @param [Boolean] value the new value to be set
|
25
|
+
#
|
26
|
+
# @return [Boolean] the current value
|
27
|
+
|
28
|
+
# @!macro atomic_boolean_method_true_question
|
29
|
+
#
|
30
|
+
# Is the current value `true`
|
31
|
+
#
|
32
|
+
# @return [Boolean] true if the current value is `true`, else false
|
33
|
+
|
34
|
+
# @!macro atomic_boolean_method_false_question
|
35
|
+
#
|
36
|
+
# Is the current value `false`
|
37
|
+
#
|
38
|
+
# @return [Boolean] true if the current value is `false`, else false
|
39
|
+
|
40
|
+
# @!macro atomic_boolean_method_make_true
|
41
|
+
#
|
42
|
+
# Explicitly sets the value to true.
|
43
|
+
#
|
44
|
+
# @return [Boolean] true is value has changed, otherwise false
|
45
|
+
|
46
|
+
# @!macro atomic_boolean_method_make_false
|
47
|
+
#
|
48
|
+
# Explicitly sets the value to false.
|
49
|
+
#
|
50
|
+
# @return [Boolean] true is value has changed, otherwise false
|
51
|
+
|
52
|
+
###################################################################
|
53
|
+
|
54
|
+
# @!macro atomic_boolean_public_api
|
55
|
+
#
|
56
|
+
# @!method initialize(initial = false)
|
57
|
+
# @!macro atomic_boolean_method_initialize
|
58
|
+
#
|
59
|
+
# @!method value
|
60
|
+
# @!macro atomic_boolean_method_value_get
|
61
|
+
#
|
62
|
+
# @!method value=(value)
|
63
|
+
# @!macro atomic_boolean_method_value_set
|
64
|
+
#
|
65
|
+
# @!method true?
|
66
|
+
# @!macro atomic_boolean_method_true_question
|
67
|
+
#
|
68
|
+
# @!method false?
|
69
|
+
# @!macro atomic_boolean_method_false_question
|
70
|
+
#
|
71
|
+
# @!method make_true
|
72
|
+
# @!macro atomic_boolean_method_make_true
|
73
|
+
#
|
74
|
+
# @!method make_false
|
75
|
+
# @!macro atomic_boolean_method_make_false
|
76
|
+
|
77
|
+
###################################################################
|
78
|
+
|
79
|
+
# @!visibility private
|
80
|
+
# @!macro internal_implementation_note
|
81
|
+
AtomicBooleanImplementation = case
|
82
|
+
when defined?(JavaAtomicBoolean)
|
83
|
+
JavaAtomicBoolean
|
84
|
+
when defined?(CAtomicBoolean)
|
85
|
+
CAtomicBoolean
|
86
|
+
else
|
87
|
+
MutexAtomicBoolean
|
88
|
+
end
|
89
|
+
private_constant :AtomicBooleanImplementation
|
90
|
+
|
91
|
+
# @!macro atomic_boolean
|
92
|
+
#
|
93
|
+
# A boolean value that can be updated atomically. Reads and writes to an atomic
|
94
|
+
# boolean and thread-safe and guaranteed to succeed. Reads and writes may block
|
95
|
+
# briefly but no explicit locking is required.
|
96
|
+
#
|
97
|
+
# @!macro thread_safe_variable_comparison
|
98
|
+
#
|
99
|
+
# Performance:
|
100
|
+
#
|
101
|
+
# ```
|
102
|
+
# Testing with ruby 2.1.2
|
103
|
+
# Testing with Concurrent::MutexAtomicBoolean...
|
104
|
+
# 2.790000 0.000000 2.790000 ( 2.791454)
|
105
|
+
# Testing with Concurrent::CAtomicBoolean...
|
106
|
+
# 0.740000 0.000000 0.740000 ( 0.740206)
|
107
|
+
#
|
108
|
+
# Testing with jruby 1.9.3
|
109
|
+
# Testing with Concurrent::MutexAtomicBoolean...
|
110
|
+
# 5.240000 2.520000 7.760000 ( 3.683000)
|
111
|
+
# Testing with Concurrent::JavaAtomicBoolean...
|
112
|
+
# 3.340000 0.010000 3.350000 ( 0.855000)
|
113
|
+
# ```
|
114
|
+
#
|
115
|
+
# @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicBoolean.html java.util.concurrent.atomic.AtomicBoolean
|
116
|
+
#
|
117
|
+
# @!macro atomic_boolean_public_api
|
118
|
+
class AtomicBoolean < AtomicBooleanImplementation
|
119
|
+
# @return [String] Short string representation.
|
120
|
+
def to_s
|
121
|
+
format '%s value:%s>', super[0..-2], value
|
122
|
+
end
|
123
|
+
|
124
|
+
alias_method :inspect, :to_s
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
require 'concurrent/atomic/mutex_atomic_fixnum'
|
2
|
+
require 'concurrent/synchronization'
|
3
|
+
|
4
|
+
module Concurrent
|
5
|
+
|
6
|
+
###################################################################
|
7
|
+
|
8
|
+
# @!macro atomic_fixnum_method_initialize
|
9
|
+
#
|
10
|
+
# Creates a new `AtomicFixnum` with the given initial value.
|
11
|
+
#
|
12
|
+
# @param [Fixnum] initial the initial value
|
13
|
+
# @raise [ArgumentError] if the initial value is not a `Fixnum`
|
14
|
+
|
15
|
+
# @!macro atomic_fixnum_method_value_get
|
16
|
+
#
|
17
|
+
# Retrieves the current `Fixnum` value.
|
18
|
+
#
|
19
|
+
# @return [Fixnum] the current value
|
20
|
+
|
21
|
+
# @!macro atomic_fixnum_method_value_set
|
22
|
+
#
|
23
|
+
# Explicitly sets the value.
|
24
|
+
#
|
25
|
+
# @param [Fixnum] value the new value to be set
|
26
|
+
#
|
27
|
+
# @return [Fixnum] the current value
|
28
|
+
#
|
29
|
+
# @raise [ArgumentError] if the new value is not a `Fixnum`
|
30
|
+
|
31
|
+
# @!macro atomic_fixnum_method_increment
|
32
|
+
#
|
33
|
+
# Increases the current value by the given amount (defaults to 1).
|
34
|
+
#
|
35
|
+
# @param [Fixnum] delta the amount by which to increase the current value
|
36
|
+
#
|
37
|
+
# @return [Fixnum] the current value after incrementation
|
38
|
+
|
39
|
+
# @!macro atomic_fixnum_method_decrement
|
40
|
+
#
|
41
|
+
# Decreases the current value by the given amount (defaults to 1).
|
42
|
+
#
|
43
|
+
# @param [Fixnum] delta the amount by which to decrease the current value
|
44
|
+
#
|
45
|
+
# @return [Fixnum] the current value after decrementation
|
46
|
+
|
47
|
+
# @!macro atomic_fixnum_method_compare_and_set
|
48
|
+
#
|
49
|
+
# Atomically sets the value to the given updated value if the current
|
50
|
+
# value == the expected value.
|
51
|
+
#
|
52
|
+
# @param [Fixnum] expect the expected value
|
53
|
+
# @param [Fixnum] update the new value
|
54
|
+
#
|
55
|
+
# @return [Boolean] true if the value was updated else false
|
56
|
+
|
57
|
+
# @!macro atomic_fixnum_method_update
|
58
|
+
#
|
59
|
+
# Pass the current value to the given block, replacing it
|
60
|
+
# with the block's result. May retry if the value changes
|
61
|
+
# during the block's execution.
|
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
|
+
#
|
67
|
+
# @return [Object] the new value
|
68
|
+
|
69
|
+
###################################################################
|
70
|
+
|
71
|
+
# @!macro atomic_fixnum_public_api
|
72
|
+
#
|
73
|
+
# @!method initialize(initial = 0)
|
74
|
+
# @!macro atomic_fixnum_method_initialize
|
75
|
+
#
|
76
|
+
# @!method value
|
77
|
+
# @!macro atomic_fixnum_method_value_get
|
78
|
+
#
|
79
|
+
# @!method value=(value)
|
80
|
+
# @!macro atomic_fixnum_method_value_set
|
81
|
+
#
|
82
|
+
# @!method increment(delta = 1)
|
83
|
+
# @!macro atomic_fixnum_method_increment
|
84
|
+
#
|
85
|
+
# @!method decrement(delta = 1)
|
86
|
+
# @!macro atomic_fixnum_method_decrement
|
87
|
+
#
|
88
|
+
# @!method compare_and_set(expect, update)
|
89
|
+
# @!macro atomic_fixnum_method_compare_and_set
|
90
|
+
#
|
91
|
+
# @!method update
|
92
|
+
# @!macro atomic_fixnum_method_update
|
93
|
+
|
94
|
+
###################################################################
|
95
|
+
|
96
|
+
# @!visibility private
|
97
|
+
# @!macro internal_implementation_note
|
98
|
+
AtomicFixnumImplementation = case
|
99
|
+
when defined?(JavaAtomicFixnum)
|
100
|
+
JavaAtomicFixnum
|
101
|
+
when defined?(CAtomicFixnum)
|
102
|
+
CAtomicFixnum
|
103
|
+
else
|
104
|
+
MutexAtomicFixnum
|
105
|
+
end
|
106
|
+
private_constant :AtomicFixnumImplementation
|
107
|
+
|
108
|
+
# @!macro atomic_fixnum
|
109
|
+
#
|
110
|
+
# A numeric value that can be updated atomically. Reads and writes to an atomic
|
111
|
+
# fixnum and thread-safe and guaranteed to succeed. Reads and writes may block
|
112
|
+
# briefly but no explicit locking is required.
|
113
|
+
#
|
114
|
+
# @!macro thread_safe_variable_comparison
|
115
|
+
#
|
116
|
+
# Performance:
|
117
|
+
#
|
118
|
+
# ```
|
119
|
+
# Testing with ruby 2.1.2
|
120
|
+
# Testing with Concurrent::MutexAtomicFixnum...
|
121
|
+
# 3.130000 0.000000 3.130000 ( 3.136505)
|
122
|
+
# Testing with Concurrent::CAtomicFixnum...
|
123
|
+
# 0.790000 0.000000 0.790000 ( 0.785550)
|
124
|
+
#
|
125
|
+
# Testing with jruby 1.9.3
|
126
|
+
# Testing with Concurrent::MutexAtomicFixnum...
|
127
|
+
# 5.460000 2.460000 7.920000 ( 3.715000)
|
128
|
+
# Testing with Concurrent::JavaAtomicFixnum...
|
129
|
+
# 4.520000 0.030000 4.550000 ( 1.187000)
|
130
|
+
# ```
|
131
|
+
#
|
132
|
+
# @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicLong.html java.util.concurrent.atomic.AtomicLong
|
133
|
+
#
|
134
|
+
# @!macro atomic_fixnum_public_api
|
135
|
+
class AtomicFixnum < AtomicFixnumImplementation
|
136
|
+
# @return [String] Short string representation.
|
137
|
+
def to_s
|
138
|
+
format '%s value:%s>', super[0..-2], value
|
139
|
+
end
|
140
|
+
|
141
|
+
alias_method :inspect, :to_s
|
142
|
+
end
|
143
|
+
end
|