o-concurrent-ruby 1.1.11
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 +7 -0
- data/CHANGELOG.md +542 -0
- data/Gemfile +37 -0
- data/LICENSE.txt +21 -0
- data/README.md +404 -0
- data/Rakefile +307 -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 +189 -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/agent.rb +587 -0
- data/lib/concurrent-ruby/concurrent/array.rb +66 -0
- data/lib/concurrent-ruby/concurrent/async.rb +449 -0
- data/lib/concurrent-ruby/concurrent/atom.rb +222 -0
- data/lib/concurrent-ruby/concurrent/atomic/abstract_thread_local_var.rb +66 -0
- data/lib/concurrent-ruby/concurrent/atomic/atomic_boolean.rb +126 -0
- data/lib/concurrent-ruby/concurrent/atomic/atomic_fixnum.rb +143 -0
- data/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb +164 -0
- data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +205 -0
- data/lib/concurrent-ruby/concurrent/atomic/count_down_latch.rb +100 -0
- data/lib/concurrent-ruby/concurrent/atomic/cyclic_barrier.rb +128 -0
- data/lib/concurrent-ruby/concurrent/atomic/event.rb +109 -0
- data/lib/concurrent-ruby/concurrent/atomic/java_count_down_latch.rb +42 -0
- data/lib/concurrent-ruby/concurrent/atomic/java_thread_local_var.rb +37 -0
- data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_boolean.rb +62 -0
- data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb +75 -0
- data/lib/concurrent-ruby/concurrent/atomic/mutex_count_down_latch.rb +44 -0
- data/lib/concurrent-ruby/concurrent/atomic/mutex_semaphore.rb +131 -0
- data/lib/concurrent-ruby/concurrent/atomic/read_write_lock.rb +254 -0
- data/lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb +377 -0
- data/lib/concurrent-ruby/concurrent/atomic/ruby_thread_local_var.rb +181 -0
- data/lib/concurrent-ruby/concurrent/atomic/semaphore.rb +166 -0
- data/lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb +104 -0
- data/lib/concurrent-ruby/concurrent/atomic_reference/mutex_atomic.rb +56 -0
- data/lib/concurrent-ruby/concurrent/atomic_reference/numeric_cas_wrapper.rb +28 -0
- data/lib/concurrent-ruby/concurrent/atomics.rb +10 -0
- data/lib/concurrent-ruby/concurrent/collection/copy_on_notify_observer_set.rb +107 -0
- data/lib/concurrent-ruby/concurrent/collection/copy_on_write_observer_set.rb +111 -0
- data/lib/concurrent-ruby/concurrent/collection/java_non_concurrent_priority_queue.rb +84 -0
- data/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb +158 -0
- data/lib/concurrent-ruby/concurrent/collection/map/atomic_reference_map_backend.rb +927 -0
- data/lib/concurrent-ruby/concurrent/collection/map/mri_map_backend.rb +66 -0
- data/lib/concurrent-ruby/concurrent/collection/map/non_concurrent_map_backend.rb +140 -0
- data/lib/concurrent-ruby/concurrent/collection/map/synchronized_map_backend.rb +82 -0
- data/lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb +14 -0
- data/lib/concurrent-ruby/concurrent/collection/non_concurrent_priority_queue.rb +143 -0
- data/lib/concurrent-ruby/concurrent/collection/ruby_non_concurrent_priority_queue.rb +160 -0
- data/lib/concurrent-ruby/concurrent/concern/deprecation.rb +34 -0
- data/lib/concurrent-ruby/concurrent/concern/dereferenceable.rb +73 -0
- data/lib/concurrent-ruby/concurrent/concern/logging.rb +32 -0
- data/lib/concurrent-ruby/concurrent/concern/obligation.rb +220 -0
- data/lib/concurrent-ruby/concurrent/concern/observable.rb +110 -0
- data/lib/concurrent-ruby/concurrent/configuration.rb +188 -0
- data/lib/concurrent-ruby/concurrent/constants.rb +8 -0
- data/lib/concurrent-ruby/concurrent/dataflow.rb +81 -0
- data/lib/concurrent-ruby/concurrent/delay.rb +199 -0
- data/lib/concurrent-ruby/concurrent/errors.rb +69 -0
- data/lib/concurrent-ruby/concurrent/exchanger.rb +352 -0
- data/lib/concurrent-ruby/concurrent/executor/abstract_executor_service.rb +131 -0
- data/lib/concurrent-ruby/concurrent/executor/cached_thread_pool.rb +62 -0
- data/lib/concurrent-ruby/concurrent/executor/executor_service.rb +185 -0
- data/lib/concurrent-ruby/concurrent/executor/fixed_thread_pool.rb +220 -0
- data/lib/concurrent-ruby/concurrent/executor/immediate_executor.rb +66 -0
- data/lib/concurrent-ruby/concurrent/executor/indirect_immediate_executor.rb +44 -0
- data/lib/concurrent-ruby/concurrent/executor/java_executor_service.rb +103 -0
- data/lib/concurrent-ruby/concurrent/executor/java_single_thread_executor.rb +30 -0
- data/lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb +140 -0
- data/lib/concurrent-ruby/concurrent/executor/ruby_executor_service.rb +82 -0
- data/lib/concurrent-ruby/concurrent/executor/ruby_single_thread_executor.rb +21 -0
- data/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb +368 -0
- data/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb +35 -0
- data/lib/concurrent-ruby/concurrent/executor/serial_executor_service.rb +34 -0
- data/lib/concurrent-ruby/concurrent/executor/serialized_execution.rb +107 -0
- data/lib/concurrent-ruby/concurrent/executor/serialized_execution_delegator.rb +28 -0
- data/lib/concurrent-ruby/concurrent/executor/simple_executor_service.rb +100 -0
- data/lib/concurrent-ruby/concurrent/executor/single_thread_executor.rb +57 -0
- data/lib/concurrent-ruby/concurrent/executor/thread_pool_executor.rb +88 -0
- data/lib/concurrent-ruby/concurrent/executor/timer_set.rb +172 -0
- data/lib/concurrent-ruby/concurrent/executors.rb +20 -0
- data/lib/concurrent-ruby/concurrent/future.rb +141 -0
- data/lib/concurrent-ruby/concurrent/hash.rb +59 -0
- data/lib/concurrent-ruby/concurrent/immutable_struct.rb +101 -0
- data/lib/concurrent-ruby/concurrent/ivar.rb +207 -0
- data/lib/concurrent-ruby/concurrent/map.rb +346 -0
- data/lib/concurrent-ruby/concurrent/maybe.rb +229 -0
- data/lib/concurrent-ruby/concurrent/mutable_struct.rb +239 -0
- data/lib/concurrent-ruby/concurrent/mvar.rb +242 -0
- data/lib/concurrent-ruby/concurrent/options.rb +42 -0
- data/lib/concurrent-ruby/concurrent/promise.rb +580 -0
- data/lib/concurrent-ruby/concurrent/promises.rb +2167 -0
- data/lib/concurrent-ruby/concurrent/re_include.rb +58 -0
- data/lib/concurrent-ruby/concurrent/scheduled_task.rb +331 -0
- data/lib/concurrent-ruby/concurrent/set.rb +74 -0
- data/lib/concurrent-ruby/concurrent/settable_struct.rb +139 -0
- data/lib/concurrent-ruby/concurrent/synchronization/abstract_lockable_object.rb +98 -0
- data/lib/concurrent-ruby/concurrent/synchronization/abstract_object.rb +24 -0
- data/lib/concurrent-ruby/concurrent/synchronization/abstract_struct.rb +171 -0
- data/lib/concurrent-ruby/concurrent/synchronization/condition.rb +60 -0
- data/lib/concurrent-ruby/concurrent/synchronization/jruby_lockable_object.rb +13 -0
- data/lib/concurrent-ruby/concurrent/synchronization/jruby_object.rb +45 -0
- data/lib/concurrent-ruby/concurrent/synchronization/lock.rb +36 -0
- data/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb +72 -0
- data/lib/concurrent-ruby/concurrent/synchronization/mri_object.rb +44 -0
- data/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb +88 -0
- data/lib/concurrent-ruby/concurrent/synchronization/object.rb +183 -0
- data/lib/concurrent-ruby/concurrent/synchronization/rbx_lockable_object.rb +71 -0
- data/lib/concurrent-ruby/concurrent/synchronization/rbx_object.rb +49 -0
- data/lib/concurrent-ruby/concurrent/synchronization/truffleruby_object.rb +47 -0
- data/lib/concurrent-ruby/concurrent/synchronization/volatile.rb +36 -0
- data/lib/concurrent-ruby/concurrent/synchronization.rb +30 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/synchronized_delegator.rb +50 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util/adder.rb +74 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util/cheap_lockable.rb +118 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +88 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util/power_of_two_tuple.rb +38 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util/striped64.rb +246 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util/volatile.rb +75 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util/xor_shift_random.rb +50 -0
- data/lib/concurrent-ruby/concurrent/thread_safe/util.rb +16 -0
- data/lib/concurrent-ruby/concurrent/timer_task.rb +311 -0
- data/lib/concurrent-ruby/concurrent/tuple.rb +86 -0
- data/lib/concurrent-ruby/concurrent/tvar.rb +221 -0
- data/lib/concurrent-ruby/concurrent/utility/engine.rb +56 -0
- data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +90 -0
- data/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb +79 -0
- data/lib/concurrent-ruby/concurrent/utility/native_integer.rb +53 -0
- data/lib/concurrent-ruby/concurrent/utility/processor_counter.rb +130 -0
- data/lib/concurrent-ruby/concurrent/version.rb +3 -0
- data/lib/concurrent-ruby/concurrent-ruby.rb +5 -0
- data/lib/concurrent-ruby/concurrent.rb +134 -0
- metadata +192 -0
@@ -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 if 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 if 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
|
@@ -0,0 +1,164 @@
|
|
1
|
+
module Concurrent
|
2
|
+
# An atomic reference which maintains an object reference along with a mark bit
|
3
|
+
# that can be updated atomically.
|
4
|
+
#
|
5
|
+
# @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicMarkableReference.html
|
6
|
+
# java.util.concurrent.atomic.AtomicMarkableReference
|
7
|
+
class AtomicMarkableReference < ::Concurrent::Synchronization::Object
|
8
|
+
|
9
|
+
attr_atomic(:reference)
|
10
|
+
private :reference, :reference=, :swap_reference, :compare_and_set_reference, :update_reference
|
11
|
+
|
12
|
+
def initialize(value = nil, mark = false)
|
13
|
+
super()
|
14
|
+
self.reference = immutable_array(value, mark)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Atomically sets the value and mark to the given updated value and
|
18
|
+
# mark given both:
|
19
|
+
# - the current value == the expected value &&
|
20
|
+
# - the current mark == the expected mark
|
21
|
+
#
|
22
|
+
# @param [Object] expected_val the expected value
|
23
|
+
# @param [Object] new_val the new value
|
24
|
+
# @param [Boolean] expected_mark the expected mark
|
25
|
+
# @param [Boolean] new_mark the new mark
|
26
|
+
#
|
27
|
+
# @return [Boolean] `true` if successful. A `false` return indicates
|
28
|
+
# that the actual value was not equal to the expected value or the
|
29
|
+
# actual mark was not equal to the expected mark
|
30
|
+
def compare_and_set(expected_val, new_val, expected_mark, new_mark)
|
31
|
+
# Memoize a valid reference to the current AtomicReference for
|
32
|
+
# later comparison.
|
33
|
+
current = reference
|
34
|
+
curr_val, curr_mark = current
|
35
|
+
|
36
|
+
# Ensure that that the expected marks match.
|
37
|
+
return false unless expected_mark == curr_mark
|
38
|
+
|
39
|
+
if expected_val.is_a? Numeric
|
40
|
+
# If the object is a numeric, we need to ensure we are comparing
|
41
|
+
# the numerical values
|
42
|
+
return false unless expected_val == curr_val
|
43
|
+
else
|
44
|
+
# Otherwise, we need to ensure we are comparing the object identity.
|
45
|
+
# Theoretically, this could be incorrect if a user monkey-patched
|
46
|
+
# `Object#equal?`, but they should know that they are playing with
|
47
|
+
# fire at that point.
|
48
|
+
return false unless expected_val.equal? curr_val
|
49
|
+
end
|
50
|
+
|
51
|
+
prospect = immutable_array(new_val, new_mark)
|
52
|
+
|
53
|
+
compare_and_set_reference current, prospect
|
54
|
+
end
|
55
|
+
|
56
|
+
alias_method :compare_and_swap, :compare_and_set
|
57
|
+
|
58
|
+
# Gets the current reference and marked values.
|
59
|
+
#
|
60
|
+
# @return [Array] the current reference and marked values
|
61
|
+
def get
|
62
|
+
reference
|
63
|
+
end
|
64
|
+
|
65
|
+
# Gets the current value of the reference
|
66
|
+
#
|
67
|
+
# @return [Object] the current value of the reference
|
68
|
+
def value
|
69
|
+
reference[0]
|
70
|
+
end
|
71
|
+
|
72
|
+
# Gets the current marked value
|
73
|
+
#
|
74
|
+
# @return [Boolean] the current marked value
|
75
|
+
def mark
|
76
|
+
reference[1]
|
77
|
+
end
|
78
|
+
|
79
|
+
alias_method :marked?, :mark
|
80
|
+
|
81
|
+
# _Unconditionally_ sets to the given value of both the reference and
|
82
|
+
# the mark.
|
83
|
+
#
|
84
|
+
# @param [Object] new_val the new value
|
85
|
+
# @param [Boolean] new_mark the new mark
|
86
|
+
#
|
87
|
+
# @return [Array] both the new value and the new mark
|
88
|
+
def set(new_val, new_mark)
|
89
|
+
self.reference = immutable_array(new_val, new_mark)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Pass the current value and marked state to the given block, replacing it
|
93
|
+
# with the block's results. May retry if the value changes during the
|
94
|
+
# block's execution.
|
95
|
+
#
|
96
|
+
# @yield [Object] Calculate a new value and marked state for the atomic
|
97
|
+
# reference using given (old) value and (old) marked
|
98
|
+
# @yieldparam [Object] old_val the starting value of the atomic reference
|
99
|
+
# @yieldparam [Boolean] old_mark the starting state of marked
|
100
|
+
#
|
101
|
+
# @return [Array] the new value and new mark
|
102
|
+
def update
|
103
|
+
loop do
|
104
|
+
old_val, old_mark = reference
|
105
|
+
new_val, new_mark = yield old_val, old_mark
|
106
|
+
|
107
|
+
if compare_and_set old_val, new_val, old_mark, new_mark
|
108
|
+
return immutable_array(new_val, new_mark)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# Pass the current value to the given block, replacing it
|
114
|
+
# with the block's result. Raise an exception if the update
|
115
|
+
# fails.
|
116
|
+
#
|
117
|
+
# @yield [Object] Calculate a new value and marked state for the atomic
|
118
|
+
# reference using given (old) value and (old) marked
|
119
|
+
# @yieldparam [Object] old_val the starting value of the atomic reference
|
120
|
+
# @yieldparam [Boolean] old_mark the starting state of marked
|
121
|
+
#
|
122
|
+
# @return [Array] the new value and marked state
|
123
|
+
#
|
124
|
+
# @raise [Concurrent::ConcurrentUpdateError] if the update fails
|
125
|
+
def try_update!
|
126
|
+
old_val, old_mark = reference
|
127
|
+
new_val, new_mark = yield old_val, old_mark
|
128
|
+
|
129
|
+
unless compare_and_set old_val, new_val, old_mark, new_mark
|
130
|
+
fail ::Concurrent::ConcurrentUpdateError,
|
131
|
+
'AtomicMarkableReference: Update failed due to race condition.',
|
132
|
+
'Note: If you would like to guarantee an update, please use ' +
|
133
|
+
'the `AtomicMarkableReference#update` method.'
|
134
|
+
end
|
135
|
+
|
136
|
+
immutable_array(new_val, new_mark)
|
137
|
+
end
|
138
|
+
|
139
|
+
# Pass the current value to the given block, replacing it with the
|
140
|
+
# block's result. Simply return nil if update fails.
|
141
|
+
#
|
142
|
+
# @yield [Object] Calculate a new value and marked state for the atomic
|
143
|
+
# reference using given (old) value and (old) marked
|
144
|
+
# @yieldparam [Object] old_val the starting value of the atomic reference
|
145
|
+
# @yieldparam [Boolean] old_mark the starting state of marked
|
146
|
+
#
|
147
|
+
# @return [Array] the new value and marked state, or nil if
|
148
|
+
# the update failed
|
149
|
+
def try_update
|
150
|
+
old_val, old_mark = reference
|
151
|
+
new_val, new_mark = yield old_val, old_mark
|
152
|
+
|
153
|
+
return unless compare_and_set old_val, new_val, old_mark, new_mark
|
154
|
+
|
155
|
+
immutable_array(new_val, new_mark)
|
156
|
+
end
|
157
|
+
|
158
|
+
private
|
159
|
+
|
160
|
+
def immutable_array(*args)
|
161
|
+
args.freeze
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,205 @@
|
|
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
|
+
TruffleRubyAtomicReference
|
174
|
+
when Concurrent.on_rbx?
|
175
|
+
# @note Extends `Rubinius::AtomicReference` version adding aliases
|
176
|
+
# and numeric logic.
|
177
|
+
#
|
178
|
+
# @!visibility private
|
179
|
+
# @!macro internal_implementation_note
|
180
|
+
class RbxAtomicReference < Rubinius::AtomicReference
|
181
|
+
alias_method :_compare_and_set, :compare_and_set
|
182
|
+
include AtomicDirectUpdate
|
183
|
+
include AtomicNumericCompareAndSetWrapper
|
184
|
+
alias_method :value, :get
|
185
|
+
alias_method :value=, :set
|
186
|
+
alias_method :swap, :get_and_set
|
187
|
+
alias_method :compare_and_swap, :compare_and_set
|
188
|
+
end
|
189
|
+
RbxAtomicReference
|
190
|
+
else
|
191
|
+
MutexAtomicReference
|
192
|
+
end
|
193
|
+
private_constant :AtomicReferenceImplementation
|
194
|
+
|
195
|
+
# @!macro atomic_reference
|
196
|
+
class AtomicReference < AtomicReferenceImplementation
|
197
|
+
|
198
|
+
# @return [String] Short string representation.
|
199
|
+
def to_s
|
200
|
+
format '%s value:%s>', super[0..-2], get
|
201
|
+
end
|
202
|
+
|
203
|
+
alias_method :inspect, :to_s
|
204
|
+
end
|
205
|
+
end
|