concurrent-ruby 0.8.0 → 0.9.0.pre2
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 +97 -2
- data/README.md +103 -54
- data/lib/concurrent.rb +34 -14
- data/lib/concurrent/async.rb +164 -50
- data/lib/concurrent/atom.rb +171 -0
- data/lib/concurrent/atomic/atomic_boolean.rb +57 -107
- data/lib/concurrent/atomic/atomic_fixnum.rb +73 -101
- data/lib/concurrent/atomic/atomic_reference.rb +49 -0
- data/lib/concurrent/atomic/condition.rb +23 -12
- data/lib/concurrent/atomic/count_down_latch.rb +23 -21
- data/lib/concurrent/atomic/cyclic_barrier.rb +47 -47
- data/lib/concurrent/atomic/event.rb +33 -42
- data/lib/concurrent/atomic/read_write_lock.rb +252 -0
- data/lib/concurrent/atomic/semaphore.rb +64 -89
- data/lib/concurrent/atomic/thread_local_var.rb +130 -58
- data/lib/concurrent/atomic/thread_local_var/weak_key_map.rb +236 -0
- data/lib/concurrent/atomic_reference/direct_update.rb +3 -0
- data/lib/concurrent/atomic_reference/jruby.rb +6 -3
- data/lib/concurrent/atomic_reference/mutex_atomic.rb +10 -32
- data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +3 -0
- data/lib/concurrent/atomic_reference/rbx.rb +4 -1
- data/lib/concurrent/atomic_reference/ruby.rb +6 -3
- data/lib/concurrent/atomics.rb +74 -4
- data/lib/concurrent/collection/copy_on_notify_observer_set.rb +115 -0
- data/lib/concurrent/collection/copy_on_write_observer_set.rb +119 -0
- data/lib/concurrent/collection/priority_queue.rb +300 -245
- data/lib/concurrent/concern/deprecation.rb +27 -0
- data/lib/concurrent/concern/dereferenceable.rb +88 -0
- data/lib/concurrent/concern/logging.rb +25 -0
- data/lib/concurrent/concern/obligation.rb +228 -0
- data/lib/concurrent/concern/observable.rb +85 -0
- data/lib/concurrent/configuration.rb +226 -112
- data/lib/concurrent/dataflow.rb +2 -3
- data/lib/concurrent/delay.rb +141 -50
- data/lib/concurrent/edge.rb +30 -0
- data/lib/concurrent/errors.rb +10 -0
- data/lib/concurrent/exchanger.rb +25 -1
- data/lib/concurrent/executor/cached_thread_pool.rb +46 -33
- data/lib/concurrent/executor/executor.rb +46 -299
- data/lib/concurrent/executor/executor_service.rb +521 -0
- data/lib/concurrent/executor/fixed_thread_pool.rb +206 -26
- data/lib/concurrent/executor/immediate_executor.rb +9 -9
- data/lib/concurrent/executor/indirect_immediate_executor.rb +4 -3
- data/lib/concurrent/executor/java_cached_thread_pool.rb +18 -16
- data/lib/concurrent/executor/java_fixed_thread_pool.rb +11 -18
- data/lib/concurrent/executor/java_single_thread_executor.rb +17 -16
- data/lib/concurrent/executor/java_thread_pool_executor.rb +55 -102
- data/lib/concurrent/executor/ruby_cached_thread_pool.rb +9 -18
- data/lib/concurrent/executor/ruby_fixed_thread_pool.rb +10 -21
- data/lib/concurrent/executor/ruby_single_thread_executor.rb +14 -16
- data/lib/concurrent/executor/ruby_thread_pool_executor.rb +250 -166
- data/lib/concurrent/executor/safe_task_executor.rb +5 -4
- data/lib/concurrent/executor/serialized_execution.rb +22 -18
- data/lib/concurrent/executor/{per_thread_executor.rb → simple_executor_service.rb} +29 -20
- data/lib/concurrent/executor/single_thread_executor.rb +32 -21
- data/lib/concurrent/executor/thread_pool_executor.rb +72 -60
- data/lib/concurrent/executor/timer_set.rb +96 -84
- data/lib/concurrent/executors.rb +1 -1
- data/lib/concurrent/future.rb +70 -38
- data/lib/concurrent/immutable_struct.rb +89 -0
- data/lib/concurrent/ivar.rb +152 -60
- data/lib/concurrent/lazy_register.rb +40 -20
- data/lib/concurrent/maybe.rb +226 -0
- data/lib/concurrent/mutable_struct.rb +227 -0
- data/lib/concurrent/mvar.rb +44 -43
- data/lib/concurrent/promise.rb +208 -134
- data/lib/concurrent/scheduled_task.rb +339 -43
- data/lib/concurrent/settable_struct.rb +127 -0
- data/lib/concurrent/synchronization.rb +17 -0
- data/lib/concurrent/synchronization/abstract_object.rb +163 -0
- data/lib/concurrent/synchronization/abstract_struct.rb +158 -0
- data/lib/concurrent/synchronization/condition.rb +53 -0
- data/lib/concurrent/synchronization/java_object.rb +35 -0
- data/lib/concurrent/synchronization/lock.rb +32 -0
- data/lib/concurrent/synchronization/monitor_object.rb +24 -0
- data/lib/concurrent/synchronization/mutex_object.rb +43 -0
- data/lib/concurrent/synchronization/object.rb +78 -0
- data/lib/concurrent/synchronization/rbx_object.rb +75 -0
- data/lib/concurrent/timer_task.rb +87 -100
- data/lib/concurrent/tvar.rb +42 -38
- data/lib/concurrent/utilities.rb +3 -1
- data/lib/concurrent/utility/at_exit.rb +97 -0
- data/lib/concurrent/utility/engine.rb +40 -0
- data/lib/concurrent/utility/monotonic_time.rb +59 -0
- data/lib/concurrent/utility/native_extension_loader.rb +56 -0
- data/lib/concurrent/utility/processor_counter.rb +156 -0
- data/lib/concurrent/utility/timeout.rb +18 -14
- data/lib/concurrent/utility/timer.rb +11 -6
- data/lib/concurrent/version.rb +2 -1
- data/lib/concurrent_ruby.rb +1 -0
- metadata +47 -83
- data/lib/concurrent/actor.rb +0 -103
- data/lib/concurrent/actor/behaviour.rb +0 -70
- data/lib/concurrent/actor/behaviour/abstract.rb +0 -48
- data/lib/concurrent/actor/behaviour/awaits.rb +0 -21
- data/lib/concurrent/actor/behaviour/buffer.rb +0 -54
- data/lib/concurrent/actor/behaviour/errors_on_unknown_message.rb +0 -12
- data/lib/concurrent/actor/behaviour/executes_context.rb +0 -18
- data/lib/concurrent/actor/behaviour/linking.rb +0 -45
- data/lib/concurrent/actor/behaviour/pausing.rb +0 -77
- data/lib/concurrent/actor/behaviour/removes_child.rb +0 -16
- data/lib/concurrent/actor/behaviour/sets_results.rb +0 -36
- data/lib/concurrent/actor/behaviour/supervised.rb +0 -59
- data/lib/concurrent/actor/behaviour/supervising.rb +0 -34
- data/lib/concurrent/actor/behaviour/terminates_children.rb +0 -13
- data/lib/concurrent/actor/behaviour/termination.rb +0 -54
- data/lib/concurrent/actor/context.rb +0 -154
- data/lib/concurrent/actor/core.rb +0 -217
- data/lib/concurrent/actor/default_dead_letter_handler.rb +0 -9
- data/lib/concurrent/actor/envelope.rb +0 -41
- data/lib/concurrent/actor/errors.rb +0 -27
- data/lib/concurrent/actor/internal_delegations.rb +0 -49
- data/lib/concurrent/actor/public_delegations.rb +0 -40
- data/lib/concurrent/actor/reference.rb +0 -81
- data/lib/concurrent/actor/root.rb +0 -37
- data/lib/concurrent/actor/type_check.rb +0 -48
- data/lib/concurrent/actor/utils.rb +0 -10
- data/lib/concurrent/actor/utils/ad_hoc.rb +0 -21
- data/lib/concurrent/actor/utils/balancer.rb +0 -42
- data/lib/concurrent/actor/utils/broadcast.rb +0 -52
- data/lib/concurrent/actor/utils/pool.rb +0 -59
- data/lib/concurrent/actress.rb +0 -3
- data/lib/concurrent/agent.rb +0 -209
- data/lib/concurrent/atomic.rb +0 -92
- data/lib/concurrent/atomic/copy_on_notify_observer_set.rb +0 -118
- data/lib/concurrent/atomic/copy_on_write_observer_set.rb +0 -117
- data/lib/concurrent/atomic/synchronization.rb +0 -51
- data/lib/concurrent/channel/buffered_channel.rb +0 -85
- data/lib/concurrent/channel/channel.rb +0 -41
- data/lib/concurrent/channel/unbuffered_channel.rb +0 -35
- data/lib/concurrent/channel/waitable_list.rb +0 -40
- data/lib/concurrent/channels.rb +0 -5
- data/lib/concurrent/collection/blocking_ring_buffer.rb +0 -71
- data/lib/concurrent/collection/ring_buffer.rb +0 -59
- data/lib/concurrent/collections.rb +0 -3
- data/lib/concurrent/dereferenceable.rb +0 -108
- data/lib/concurrent/executor/ruby_thread_pool_worker.rb +0 -73
- data/lib/concurrent/logging.rb +0 -20
- data/lib/concurrent/obligation.rb +0 -171
- data/lib/concurrent/observable.rb +0 -73
- data/lib/concurrent/options_parser.rb +0 -52
- data/lib/concurrent/utility/processor_count.rb +0 -152
- data/lib/extension_helper.rb +0 -37
@@ -0,0 +1,171 @@
|
|
1
|
+
require 'concurrent/concern/dereferenceable'
|
2
|
+
require 'concurrent/atomic/atomic_reference'
|
3
|
+
require 'concurrent/synchronization/object'
|
4
|
+
|
5
|
+
module Concurrent
|
6
|
+
|
7
|
+
# Atoms provide a way to manage shared, synchronous, independent state.
|
8
|
+
#
|
9
|
+
# An atom is initialized with an initial value and an optional validation
|
10
|
+
# proc. At any time the value of the atom can be synchronously and safely
|
11
|
+
# changed. If a validator is given at construction then any new value
|
12
|
+
# will be checked against the validator and will be rejected if the
|
13
|
+
# validator returns false or raises an exception.
|
14
|
+
#
|
15
|
+
# There are two ways to change the value of an atom: {#compare_and_set} and
|
16
|
+
# {#swap}. The former will set the new value if and only if it validates and
|
17
|
+
# the current value matches the new value. The latter will atomically set the
|
18
|
+
# new value to the result of running the given block if and only if that
|
19
|
+
# value validates.
|
20
|
+
#
|
21
|
+
# @!macro [attach] copy_options
|
22
|
+
# ## Copy Options
|
23
|
+
#
|
24
|
+
# Object references in Ruby are mutable. This can lead to serious
|
25
|
+
# problems when the {#value} of an object is a mutable reference. Which
|
26
|
+
# is always the case unless the value is a `Fixnum`, `Symbol`, or similar
|
27
|
+
# "primative" data type. Each instance can be configured with a few
|
28
|
+
# options that can help protect the program from potentially dangerous
|
29
|
+
# operations. Each of these options can be optionally set when the oject
|
30
|
+
# instance is created:
|
31
|
+
#
|
32
|
+
# * `:dup_on_deref` When true the object will call the `#dup` method on
|
33
|
+
# the `value` object every time the `#value` methid is called
|
34
|
+
# (default: false)
|
35
|
+
# * `:freeze_on_deref` When true the object will call the `#freeze`
|
36
|
+
# method on the `value` object every time the `#value` method is called
|
37
|
+
# (default: false)
|
38
|
+
# * `:copy_on_deref` When given a `Proc` object the `Proc` will be run
|
39
|
+
# every time the `#value` method is called. The `Proc` will be given
|
40
|
+
# the current `value` as its only argument and the result returned by
|
41
|
+
# the block will be the return value of the `#value` call. When `nil`
|
42
|
+
# this option will be ignored (default: nil)
|
43
|
+
#
|
44
|
+
# When multiple deref options are set the order of operations is strictly defined.
|
45
|
+
# The order of deref operations is:
|
46
|
+
# * `:copy_on_deref`
|
47
|
+
# * `:dup_on_deref`
|
48
|
+
# * `:freeze_on_deref`
|
49
|
+
#
|
50
|
+
# Because of this ordering there is no need to `#freeze` an object created by a
|
51
|
+
# provided `:copy_on_deref` block. Simply set `:freeze_on_deref` to `true`.
|
52
|
+
# Setting both `:dup_on_deref` to `true` and `:freeze_on_deref` to `true` is
|
53
|
+
# as close to the behavior of a "pure" functional language (like Erlang, Clojure,
|
54
|
+
# or Haskell) as we are likely to get in Ruby.
|
55
|
+
#
|
56
|
+
# @see http://clojure.org/atoms Clojure Atoms
|
57
|
+
class Atom < Synchronization::Object
|
58
|
+
include Concern::Dereferenceable
|
59
|
+
|
60
|
+
# Create a new atom with the given initial value.
|
61
|
+
#
|
62
|
+
# @param [Object] value The initial value
|
63
|
+
# @param [Hash] opts The options used to configure the atom
|
64
|
+
# @option opts [Proc] :validator (nil) Optional proc used to validate new
|
65
|
+
# values. It must accept one and only one argument which will be the
|
66
|
+
# intended new value. The validator will return true if the new value
|
67
|
+
# is acceptable else return false (preferrably) or raise an exception.
|
68
|
+
#
|
69
|
+
# @!macro [attach] deref_options
|
70
|
+
# @option opts [Boolean] :dup_on_deref (false) Call `#dup` before
|
71
|
+
# returning the data from {#value}
|
72
|
+
# @option opts [Boolean] :freeze_on_deref (false) Call `#freeze` before
|
73
|
+
# returning the data from {#value}
|
74
|
+
# @option opts [Proc] :copy_on_deref (nil) When calling the {#value}
|
75
|
+
# method, call the given proc passing the internal value as the sole
|
76
|
+
# argument then return the new value returned from the proc.
|
77
|
+
#
|
78
|
+
# @raise [ArgumentError] if the validator is not a `Proc` (when given)
|
79
|
+
def initialize(value, opts = {})
|
80
|
+
super()
|
81
|
+
|
82
|
+
@validator = opts.fetch(:validator, ->(v){ true })
|
83
|
+
raise ArgumentError.new('validator must be a proc') unless @validator.is_a? Proc
|
84
|
+
|
85
|
+
@value = Concurrent::AtomicReference.new(value)
|
86
|
+
ns_set_deref_options(opts)
|
87
|
+
ensure_ivar_visibility!
|
88
|
+
end
|
89
|
+
|
90
|
+
# The current value of the atom.
|
91
|
+
#
|
92
|
+
# @return [Object] The current value.
|
93
|
+
def value
|
94
|
+
apply_deref_options(@value.value)
|
95
|
+
end
|
96
|
+
alias_method :deref, :value
|
97
|
+
|
98
|
+
# Atomically swaps the value of atom using the given block. The current
|
99
|
+
# value will be passed to the block, as will any arguments passed as
|
100
|
+
# arguments to the function. The new value will be validated against the
|
101
|
+
# (optional) validator proc given at construction. If validation fails the
|
102
|
+
# value will not be changed.
|
103
|
+
#
|
104
|
+
# Internally, {#swap} reads the current value, applies the block to it, and
|
105
|
+
# attempts to compare-and-set it in. Since another thread may have changed
|
106
|
+
# the value in the intervening time, it may have to retry, and does so in a
|
107
|
+
# spin loop. The net effect is that the value will always be the result of
|
108
|
+
# the application of the supplied block to a current value, atomically.
|
109
|
+
# However, because the block might be called multiple times, it must be free
|
110
|
+
# of side effects.
|
111
|
+
#
|
112
|
+
# @note The given block may be called multiple times, and thus should be free
|
113
|
+
# of side effects.
|
114
|
+
#
|
115
|
+
# @param [Object] args Zero or more arguments passed to the block.
|
116
|
+
#
|
117
|
+
# @yield [value, args] Calculates a new value for the atom based on the
|
118
|
+
# current value and any supplied agruments.
|
119
|
+
# @yieldparam value [Object] The current value of the atom.
|
120
|
+
# @yieldparam args [Object] All arguments passed to the function, in order.
|
121
|
+
# @yieldreturn [Object] The intended new value of the atom.
|
122
|
+
#
|
123
|
+
# @return [Object] The final value of the atom after all operations and
|
124
|
+
# validations are complete.
|
125
|
+
#
|
126
|
+
# @raise [ArgumentError] When no block is given.
|
127
|
+
def swap(*args)
|
128
|
+
raise ArgumentError.new('no block given') unless block_given?
|
129
|
+
|
130
|
+
begin
|
131
|
+
loop do
|
132
|
+
old_value = @value.value
|
133
|
+
new_value = yield(old_value, *args)
|
134
|
+
return old_value unless @validator.call(new_value)
|
135
|
+
return new_value if compare_and_set!(old_value, new_value)
|
136
|
+
end
|
137
|
+
rescue
|
138
|
+
return @value.value
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# @!macro [attach] atom_compare_and_set
|
143
|
+
# Atomically sets the value of atom to the new value if and only if the
|
144
|
+
# current value of the atom is identical to the old value and the new
|
145
|
+
# value successfully validates against the (optional) validator given
|
146
|
+
# at construction.
|
147
|
+
#
|
148
|
+
# @param [Object] old_value The expected current value.
|
149
|
+
# @param [Object] new_value The intended new value.
|
150
|
+
#
|
151
|
+
# @return [Boolean] True if the value is changed else false.
|
152
|
+
def compare_and_set(old_value, new_value)
|
153
|
+
compare_and_set!(old_value, new_value)
|
154
|
+
rescue
|
155
|
+
false
|
156
|
+
end
|
157
|
+
|
158
|
+
private
|
159
|
+
|
160
|
+
# @!macro atom_compare_and_set
|
161
|
+
# @raise [Exception] if the validator proc raises an exception
|
162
|
+
# @!visibility private
|
163
|
+
def compare_and_set!(old_value, new_value)
|
164
|
+
if @validator.call(new_value) # may raise exception
|
165
|
+
@value.compare_and_set(old_value, new_value)
|
166
|
+
else
|
167
|
+
false
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
|
-
|
1
|
+
require 'concurrent/utility/native_extension_loader'
|
2
|
+
require 'concurrent/synchronization'
|
2
3
|
|
3
4
|
module Concurrent
|
4
5
|
|
@@ -21,7 +22,11 @@ module Concurrent
|
|
21
22
|
# 3.340000 0.010000 3.350000 ( 0.855000)
|
22
23
|
#
|
23
24
|
# @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicBoolean.html java.util.concurrent.atomic.AtomicBoolean
|
24
|
-
|
25
|
+
#
|
26
|
+
# @!visibility private
|
27
|
+
#
|
28
|
+
# @!macro internal_implementation_note
|
29
|
+
class MutexAtomicBoolean < Synchronization::Object
|
25
30
|
|
26
31
|
# @!macro [attach] atomic_boolean_method_initialize
|
27
32
|
#
|
@@ -29,8 +34,8 @@ module Concurrent
|
|
29
34
|
#
|
30
35
|
# @param [Boolean] initial the initial value
|
31
36
|
def initialize(initial = false)
|
32
|
-
|
33
|
-
|
37
|
+
super()
|
38
|
+
synchronize { ns_initialize(initial) }
|
34
39
|
end
|
35
40
|
|
36
41
|
# @!macro [attach] atomic_boolean_method_value_get
|
@@ -39,10 +44,7 @@ module Concurrent
|
|
39
44
|
#
|
40
45
|
# @return [Boolean] the current value
|
41
46
|
def value
|
42
|
-
@
|
43
|
-
@value
|
44
|
-
ensure
|
45
|
-
@mutex.unlock
|
47
|
+
synchronize { @value }
|
46
48
|
end
|
47
49
|
|
48
50
|
# @!macro [attach] atomic_boolean_method_value_set
|
@@ -53,11 +55,7 @@ module Concurrent
|
|
53
55
|
#
|
54
56
|
# @return [Boolean] the current value
|
55
57
|
def value=(value)
|
56
|
-
@
|
57
|
-
@value = !!value
|
58
|
-
@value
|
59
|
-
ensure
|
60
|
-
@mutex.unlock
|
58
|
+
synchronize { @value = !!value }
|
61
59
|
end
|
62
60
|
|
63
61
|
# @!macro [attach] atomic_boolean_method_true_question
|
@@ -66,22 +64,16 @@ module Concurrent
|
|
66
64
|
#
|
67
65
|
# @return [Boolean] true if the current value is `true`, else false
|
68
66
|
def true?
|
69
|
-
@
|
70
|
-
@value
|
71
|
-
ensure
|
72
|
-
@mutex.unlock
|
67
|
+
synchronize { @value }
|
73
68
|
end
|
74
69
|
|
75
|
-
# @!macro atomic_boolean_method_false_question
|
70
|
+
# @!macro [attach] atomic_boolean_method_false_question
|
76
71
|
#
|
77
72
|
# Is the current value `false`
|
78
73
|
#
|
79
74
|
# @return [Boolean] true if the current value is `false`, else false
|
80
75
|
def false?
|
81
|
-
|
82
|
-
!@value
|
83
|
-
ensure
|
84
|
-
@mutex.unlock
|
76
|
+
synchronize { !@value }
|
85
77
|
end
|
86
78
|
|
87
79
|
# @!macro [attach] atomic_boolean_method_make_true
|
@@ -90,12 +82,7 @@ module Concurrent
|
|
90
82
|
#
|
91
83
|
# @return [Boolean] true is value has changed, otherwise false
|
92
84
|
def make_true
|
93
|
-
|
94
|
-
old = @value
|
95
|
-
@value = true
|
96
|
-
!old
|
97
|
-
ensure
|
98
|
-
@mutex.unlock
|
85
|
+
synchronize { ns_make_value(true) }
|
99
86
|
end
|
100
87
|
|
101
88
|
# @!macro [attach] atomic_boolean_method_make_false
|
@@ -104,98 +91,61 @@ module Concurrent
|
|
104
91
|
#
|
105
92
|
# @return [Boolean] true is value has changed, otherwise false
|
106
93
|
def make_false
|
107
|
-
|
108
|
-
old = @value
|
109
|
-
@value = false
|
110
|
-
old
|
111
|
-
ensure
|
112
|
-
@mutex.unlock
|
94
|
+
synchronize { ns_make_value(false) }
|
113
95
|
end
|
114
|
-
end
|
115
96
|
|
116
|
-
|
117
|
-
|
118
|
-
# @!macro atomic_boolean
|
119
|
-
class JavaAtomicBoolean
|
120
|
-
|
121
|
-
# @!macro atomic_boolean_method_initialize
|
122
|
-
#
|
123
|
-
def initialize(initial = false)
|
124
|
-
@atomic = java.util.concurrent.atomic.AtomicBoolean.new(!!initial)
|
125
|
-
end
|
126
|
-
|
127
|
-
# @!macro atomic_boolean_method_value_get
|
128
|
-
#
|
129
|
-
def value
|
130
|
-
@atomic.get
|
131
|
-
end
|
132
|
-
|
133
|
-
# @!macro atomic_boolean_method_value_set
|
134
|
-
#
|
135
|
-
def value=(value)
|
136
|
-
@atomic.set(!!value)
|
137
|
-
end
|
138
|
-
|
139
|
-
# @!macro atomic_boolean_method_true_question
|
140
|
-
def true?
|
141
|
-
@atomic.get
|
142
|
-
end
|
143
|
-
|
144
|
-
# @!macro atomic_boolean_method_false_question
|
145
|
-
def false?
|
146
|
-
!@atomic.get
|
147
|
-
end
|
148
|
-
|
149
|
-
# @!macro atomic_boolean_method_make_true
|
150
|
-
def make_true
|
151
|
-
@atomic.compareAndSet(false, true)
|
152
|
-
end
|
153
|
-
|
154
|
-
# @!macro atomic_boolean_method_make_false
|
155
|
-
def make_false
|
156
|
-
@atomic.compareAndSet(true, false)
|
157
|
-
end
|
158
|
-
end
|
97
|
+
protected
|
159
98
|
|
160
|
-
# @!
|
161
|
-
|
99
|
+
# @!visibility private
|
100
|
+
def ns_initialize(initial)
|
101
|
+
@value = !!initial
|
162
102
|
end
|
163
103
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
104
|
+
# @!visibility private
|
105
|
+
def ns_make_value(value)
|
106
|
+
old = @value
|
107
|
+
@value = value
|
108
|
+
old != @value
|
109
|
+
end
|
110
|
+
end
|
171
111
|
|
172
|
-
|
173
|
-
|
112
|
+
# @!visibility private
|
113
|
+
# @!macro internal_implementation_note
|
114
|
+
AtomicBooleanImplementation = case
|
115
|
+
when Concurrent.on_jruby?
|
116
|
+
JavaAtomicBoolean
|
117
|
+
when defined?(CAtomicBoolean)
|
118
|
+
CAtomicBoolean
|
119
|
+
else
|
120
|
+
MutexAtomicBoolean
|
121
|
+
end
|
122
|
+
private_constant :AtomicBooleanImplementation
|
123
|
+
|
124
|
+
# @!macro atomic_boolean
|
125
|
+
#
|
126
|
+
# @see Concurrent::MutexAtomicBoolean
|
127
|
+
class AtomicBoolean < AtomicBooleanImplementation
|
174
128
|
|
175
|
-
|
176
|
-
|
129
|
+
# @!method initialize(initial = false)
|
130
|
+
# @!macro atomic_boolean_method_initialize
|
177
131
|
|
178
|
-
|
179
|
-
|
132
|
+
# @!method value
|
133
|
+
# @!macro atomic_boolean_method_value_get
|
180
134
|
|
181
|
-
|
182
|
-
|
135
|
+
# @!method value=(value)
|
136
|
+
# @!macro atomic_boolean_method_value_set
|
183
137
|
|
184
|
-
|
185
|
-
|
138
|
+
# @!method true?
|
139
|
+
# @!macro atomic_boolean_method_true_question
|
186
140
|
|
187
|
-
|
188
|
-
|
189
|
-
end
|
141
|
+
# @!method false?
|
142
|
+
# @!macro atomic_boolean_method_false_question
|
190
143
|
|
191
|
-
# @!
|
192
|
-
|
193
|
-
end
|
144
|
+
# @!method make_true
|
145
|
+
# @!macro atomic_boolean_method_make_true
|
194
146
|
|
195
|
-
|
147
|
+
# @!method make_false
|
148
|
+
# @!macro atomic_boolean_method_make_false
|
196
149
|
|
197
|
-
# @!macro atomic_boolean
|
198
|
-
class AtomicBoolean < MutexAtomicBoolean
|
199
|
-
end
|
200
150
|
end
|
201
151
|
end
|
@@ -1,4 +1,5 @@
|
|
1
|
-
|
1
|
+
require 'concurrent/utility/native_extension_loader'
|
2
|
+
require 'concurrent/synchronization'
|
2
3
|
|
3
4
|
module Concurrent
|
4
5
|
|
@@ -21,7 +22,10 @@ module Concurrent
|
|
21
22
|
# 4.520000 0.030000 4.550000 ( 1.187000)
|
22
23
|
#
|
23
24
|
# @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicLong.html java.util.concurrent.atomic.AtomicLong
|
24
|
-
|
25
|
+
#
|
26
|
+
# @!visibility private
|
27
|
+
# @!macro internal_implementation_note
|
28
|
+
class MutexAtomicFixnum < Synchronization::Object
|
25
29
|
|
26
30
|
# http://stackoverflow.com/questions/535721/ruby-max-integer
|
27
31
|
MIN_VALUE = -(2**(0.size * 8 - 2))
|
@@ -31,12 +35,11 @@ module Concurrent
|
|
31
35
|
#
|
32
36
|
# Creates a new `AtomicFixnum` with the given initial value.
|
33
37
|
#
|
34
|
-
# @param [Fixnum]
|
38
|
+
# @param [Fixnum] initial the initial value
|
35
39
|
# @raise [ArgumentError] if the initial value is not a `Fixnum`
|
36
|
-
def initialize(
|
37
|
-
|
38
|
-
|
39
|
-
@mutex = Mutex.new
|
40
|
+
def initialize(initial = 0)
|
41
|
+
super()
|
42
|
+
synchronize { ns_initialize(initial) }
|
40
43
|
end
|
41
44
|
|
42
45
|
# @!macro [attach] atomic_fixnum_method_value_get
|
@@ -45,10 +48,7 @@ module Concurrent
|
|
45
48
|
#
|
46
49
|
# @return [Fixnum] the current value
|
47
50
|
def value
|
48
|
-
@
|
49
|
-
@value
|
50
|
-
ensure
|
51
|
-
@mutex.unlock
|
51
|
+
synchronize { @value }
|
52
52
|
end
|
53
53
|
|
54
54
|
# @!macro [attach] atomic_fixnum_method_value_set
|
@@ -61,11 +61,7 @@ module Concurrent
|
|
61
61
|
#
|
62
62
|
# @raise [ArgumentError] if the new value is not a `Fixnum`
|
63
63
|
def value=(value)
|
64
|
-
|
65
|
-
@mutex.lock
|
66
|
-
@value = value
|
67
|
-
ensure
|
68
|
-
@mutex.unlock
|
64
|
+
synchronize { ns_set(value) }
|
69
65
|
end
|
70
66
|
|
71
67
|
# @!macro [attach] atomic_fixnum_method_increment
|
@@ -74,10 +70,7 @@ module Concurrent
|
|
74
70
|
#
|
75
71
|
# @return [Fixnum] the current value after incrementation
|
76
72
|
def increment
|
77
|
-
@
|
78
|
-
@value += 1
|
79
|
-
ensure
|
80
|
-
@mutex.unlock
|
73
|
+
synchronize { ns_set(@value + 1) }
|
81
74
|
end
|
82
75
|
|
83
76
|
alias_method :up, :increment
|
@@ -88,115 +81,94 @@ module Concurrent
|
|
88
81
|
#
|
89
82
|
# @return [Fixnum] the current value after decrementation
|
90
83
|
def decrement
|
91
|
-
@
|
92
|
-
@value -= 1
|
93
|
-
ensure
|
94
|
-
@mutex.unlock
|
84
|
+
synchronize { ns_set(@value -1) }
|
95
85
|
end
|
96
86
|
|
97
87
|
alias_method :down, :decrement
|
98
88
|
|
99
89
|
# @!macro [attach] atomic_fixnum_method_compare_and_set
|
100
|
-
#
|
90
|
+
#
|
101
91
|
# Atomically sets the value to the given updated value if the current
|
102
92
|
# value == the expected value.
|
103
93
|
#
|
104
94
|
# @param [Fixnum] expect the expected value
|
105
95
|
# @param [Fixnum] update the new value
|
106
96
|
#
|
107
|
-
# @return [
|
97
|
+
# @return [Fixnum] true if the value was updated else false
|
108
98
|
def compare_and_set(expect, update)
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
99
|
+
synchronize do
|
100
|
+
if @value == expect
|
101
|
+
@value = update
|
102
|
+
true
|
103
|
+
else
|
104
|
+
false
|
105
|
+
end
|
115
106
|
end
|
116
|
-
ensure
|
117
|
-
@mutex.unlock
|
118
107
|
end
|
119
|
-
end
|
120
|
-
|
121
|
-
if RUBY_PLATFORM == 'java'
|
122
|
-
|
123
|
-
# @!macro atomic_fixnum
|
124
|
-
class JavaAtomicFixnum
|
125
108
|
|
126
|
-
|
127
|
-
MAX_VALUE = Java::JavaLang::Long::MAX_VALUE
|
109
|
+
protected
|
128
110
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
end
|
134
|
-
|
135
|
-
# @!macro atomic_fixnum_method_value_get
|
136
|
-
def value
|
137
|
-
@atomic.get
|
138
|
-
end
|
139
|
-
|
140
|
-
# @!macro atomic_fixnum_method_value_set
|
141
|
-
def value=(value)
|
142
|
-
raise ArgumentError.new('value must be a Fixnum') unless value.is_a?(Fixnum)
|
143
|
-
@atomic.set(value)
|
144
|
-
end
|
145
|
-
|
146
|
-
# @!macro atomic_fixnum_method_increment
|
147
|
-
def increment
|
148
|
-
@atomic.increment_and_get
|
149
|
-
end
|
150
|
-
alias_method :up, :increment
|
111
|
+
# @!visibility private
|
112
|
+
def ns_initialize(initial)
|
113
|
+
ns_set(initial)
|
114
|
+
end
|
151
115
|
|
152
|
-
|
153
|
-
def decrement
|
154
|
-
@atomic.decrement_and_get
|
155
|
-
end
|
156
|
-
alias_method :down, :decrement
|
116
|
+
private
|
157
117
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
118
|
+
# @!visibility private
|
119
|
+
def ns_set(value)
|
120
|
+
range_check!(value)
|
121
|
+
@value = value
|
162
122
|
end
|
163
123
|
|
164
|
-
# @!
|
165
|
-
|
124
|
+
# @!visibility private
|
125
|
+
def range_check!(value)
|
126
|
+
if !value.is_a?(Fixnum)
|
127
|
+
raise ArgumentError.new('value value must be a Fixnum')
|
128
|
+
elsif value > MAX_VALUE
|
129
|
+
raise RangeError.new("#{value} is greater than the maximum value of #{MAX_VALUE}")
|
130
|
+
elsif value < MIN_VALUE
|
131
|
+
raise RangeError.new("#{value} is less than the maximum value of #{MIN_VALUE}")
|
132
|
+
else
|
133
|
+
value
|
134
|
+
end
|
166
135
|
end
|
136
|
+
end
|
167
137
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
138
|
+
# @!visibility private
|
139
|
+
# @!macro internal_implementation_note
|
140
|
+
AtomicFixnumImplementation = case
|
141
|
+
when Concurrent.on_jruby?
|
142
|
+
JavaAtomicFixnum
|
143
|
+
when defined?(CAtomicFixnum)
|
144
|
+
CAtomicFixnum
|
145
|
+
else
|
146
|
+
MutexAtomicFixnum
|
147
|
+
end
|
148
|
+
private_constant :AtomicFixnumImplementation
|
149
|
+
|
150
|
+
# @!macro atomic_fixnum
|
151
|
+
#
|
152
|
+
# @see Concurrent::MutexAtomicFixnum
|
153
|
+
class AtomicFixnum < AtomicFixnumImplementation
|
172
154
|
|
173
|
-
|
174
|
-
|
155
|
+
# @!method initialize(initial = 0)
|
156
|
+
# @!macro atomic_fixnum_method_initialize
|
175
157
|
|
176
|
-
|
177
|
-
|
158
|
+
# @!method value
|
159
|
+
# @!macro atomic_fixnum_method_value_get
|
178
160
|
|
179
|
-
|
180
|
-
|
161
|
+
# @!method value=(value)
|
162
|
+
# @!macro atomic_fixnum_method_value_set
|
181
163
|
|
182
|
-
|
183
|
-
|
164
|
+
# @!method increment
|
165
|
+
# @!macro atomic_fixnum_method_increment
|
184
166
|
|
185
|
-
|
186
|
-
|
167
|
+
# @!method decrement
|
168
|
+
# @!macro atomic_fixnum_method_decrement
|
187
169
|
|
188
|
-
|
189
|
-
|
190
|
-
end
|
170
|
+
# @!method compare_and_set(expect, update)
|
171
|
+
# @!macro atomic_fixnum_method_compare_and_set
|
191
172
|
|
192
|
-
# @!macro atomic_fixnum
|
193
|
-
class AtomicFixnum < CAtomicFixnum
|
194
|
-
end
|
195
|
-
|
196
|
-
else
|
197
|
-
|
198
|
-
# @!macro atomic_fixnum
|
199
|
-
class AtomicFixnum < MutexAtomicFixnum
|
200
|
-
end
|
201
173
|
end
|
202
174
|
end
|