concurrent-ruby 1.0.5 → 1.1.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +42 -0
- data/Gemfile +39 -0
- data/{LICENSE.txt → LICENSE.md} +2 -0
- data/README.md +203 -105
- data/Rakefile +278 -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 +304 -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 +24 -20
- data/lib/concurrent/agent.rb +7 -7
- data/lib/concurrent/array.rb +59 -32
- data/lib/concurrent/async.rb +4 -4
- data/lib/concurrent/atom.rb +9 -9
- data/lib/concurrent/atomic/atomic_boolean.rb +24 -20
- data/lib/concurrent/atomic/atomic_fixnum.rb +27 -23
- data/lib/concurrent/atomic/atomic_markable_reference.rb +164 -0
- data/lib/concurrent/atomic/atomic_reference.rb +176 -33
- data/lib/concurrent/atomic/count_down_latch.rb +6 -6
- data/lib/concurrent/atomic/cyclic_barrier.rb +1 -1
- data/lib/concurrent/atomic/event.rb +1 -1
- data/lib/concurrent/atomic/java_count_down_latch.rb +6 -5
- data/lib/concurrent/atomic/mutex_count_down_latch.rb +1 -0
- data/lib/concurrent/atomic/read_write_lock.rb +2 -1
- data/lib/concurrent/atomic/reentrant_read_write_lock.rb +3 -1
- data/lib/concurrent/atomic/semaphore.rb +8 -8
- data/lib/concurrent/atomic/thread_local_var.rb +7 -7
- data/lib/concurrent/atomic_reference/mutex_atomic.rb +3 -8
- data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +1 -1
- data/lib/concurrent/atomics.rb +0 -43
- data/lib/concurrent/collection/lock_free_stack.rb +127 -0
- data/lib/concurrent/collection/map/atomic_reference_map_backend.rb +3 -3
- data/lib/concurrent/collection/map/non_concurrent_map_backend.rb +1 -2
- data/lib/concurrent/collection/non_concurrent_priority_queue.rb +29 -29
- data/lib/concurrent/concern/dereferenceable.rb +1 -1
- data/lib/concurrent/concern/logging.rb +6 -1
- data/lib/concurrent/concern/observable.rb +7 -7
- data/lib/concurrent/concurrent_ruby.jar +0 -0
- data/lib/concurrent/configuration.rb +1 -6
- data/lib/concurrent/constants.rb +1 -1
- data/lib/concurrent/dataflow.rb +2 -1
- data/lib/concurrent/delay.rb +9 -7
- data/lib/concurrent/exchanger.rb +13 -21
- data/lib/concurrent/executor/abstract_executor_service.rb +2 -2
- data/lib/concurrent/executor/cached_thread_pool.rb +1 -1
- data/lib/concurrent/executor/executor_service.rb +15 -15
- data/lib/concurrent/executor/fixed_thread_pool.rb +18 -18
- data/lib/concurrent/executor/java_thread_pool_executor.rb +10 -7
- data/lib/concurrent/executor/single_thread_executor.rb +2 -2
- data/lib/concurrent/executor/thread_pool_executor.rb +6 -6
- data/lib/concurrent/executor/timer_set.rb +1 -1
- data/lib/concurrent/future.rb +4 -1
- data/lib/concurrent/hash.rb +53 -30
- data/lib/concurrent/ivar.rb +5 -6
- data/lib/concurrent/map.rb +20 -25
- data/lib/concurrent/maybe.rb +1 -1
- data/lib/concurrent/mutable_struct.rb +15 -14
- data/lib/concurrent/mvar.rb +2 -2
- data/lib/concurrent/promise.rb +53 -21
- data/lib/concurrent/promises.rb +1938 -0
- data/lib/concurrent/re_include.rb +58 -0
- data/lib/concurrent/set.rb +66 -0
- data/lib/concurrent/settable_struct.rb +1 -0
- data/lib/concurrent/synchronization.rb +4 -5
- data/lib/concurrent/synchronization/abstract_lockable_object.rb +5 -5
- data/lib/concurrent/synchronization/abstract_struct.rb +6 -4
- data/lib/concurrent/synchronization/lockable_object.rb +6 -6
- data/lib/concurrent/synchronization/{mri_lockable_object.rb → mutex_lockable_object.rb} +19 -14
- data/lib/concurrent/synchronization/object.rb +8 -4
- data/lib/concurrent/synchronization/truffleruby_object.rb +46 -0
- data/lib/concurrent/synchronization/volatile.rb +11 -9
- data/lib/concurrent/thread_safe/util/data_structures.rb +55 -0
- data/lib/concurrent/thread_safe/util/striped64.rb +9 -4
- data/lib/concurrent/timer_task.rb +5 -2
- data/lib/concurrent/tuple.rb +1 -1
- data/lib/concurrent/tvar.rb +2 -2
- data/lib/concurrent/utility/at_exit.rb +1 -1
- data/lib/concurrent/utility/engine.rb +2 -2
- data/lib/concurrent/utility/monotonic_time.rb +3 -3
- data/lib/concurrent/utility/native_extension_loader.rb +31 -33
- data/lib/concurrent/utility/processor_counter.rb +0 -2
- data/lib/concurrent/version.rb +2 -2
- metadata +35 -21
- data/lib/concurrent/atomic_reference/concurrent_update_error.rb +0 -8
- data/lib/concurrent/atomic_reference/direct_update.rb +0 -81
- data/lib/concurrent/atomic_reference/jruby+truffle.rb +0 -2
- data/lib/concurrent/atomic_reference/jruby.rb +0 -16
- data/lib/concurrent/atomic_reference/rbx.rb +0 -22
- data/lib/concurrent/atomic_reference/ruby.rb +0 -32
- data/lib/concurrent/edge.rb +0 -26
- data/lib/concurrent/lazy_register.rb +0 -81
- data/lib/concurrent/synchronization/truffle_lockable_object.rb +0 -9
- data/lib/concurrent/synchronization/truffle_object.rb +0 -31
- data/lib/concurrent/thread_safe/util/array_hash_rbx.rb +0 -30
data/lib/concurrent/async.rb
CHANGED
@@ -159,7 +159,7 @@ module Concurrent
|
|
159
159
|
#
|
160
160
|
# To get the state *at the current* time, irrespective of an enqueued method
|
161
161
|
# calls, a reader method must be called directly. This is inherently unsafe
|
162
|
-
# unless the instance variable is itself thread-safe,
|
162
|
+
# unless the instance variable is itself thread-safe, preferably using one
|
163
163
|
# of the thread-safe classes within this library. Because the thread-safe
|
164
164
|
# classes within this library are internally-locking or non-locking, they can
|
165
165
|
# be safely used from within asynchronous methods without causing deadlocks.
|
@@ -188,7 +188,7 @@ module Concurrent
|
|
188
188
|
#
|
189
189
|
# Class variables should be avoided. Class variables represent shared state.
|
190
190
|
# Shared state is anathema to concurrency. Should there be a need to share
|
191
|
-
# state using class variables they *must* be thread-safe,
|
191
|
+
# state using class variables they *must* be thread-safe, preferably
|
192
192
|
# using the thread-safe classes within this library. When updating class
|
193
193
|
# variables, never assign a new value/object to the variable itself. Assignment
|
194
194
|
# is not thread-safe in Ruby. Instead, use the thread-safe update functions
|
@@ -392,7 +392,7 @@ module Concurrent
|
|
392
392
|
# object's thread. The final disposition of the method call can be obtained
|
393
393
|
# by inspecting the returned future.
|
394
394
|
#
|
395
|
-
# @!macro
|
395
|
+
# @!macro async_thread_safety_warning
|
396
396
|
# @note The method call is guaranteed to be thread safe with respect to
|
397
397
|
# all other method calls against the same object that are called with
|
398
398
|
# either `async` or `await`. The mutable nature of Ruby references
|
@@ -435,7 +435,7 @@ module Concurrent
|
|
435
435
|
#
|
436
436
|
# @!visibility private
|
437
437
|
def init_synchronization
|
438
|
-
return self if @__async_initialized__
|
438
|
+
return self if defined?(@__async_initialized__) && @__async_initialized__
|
439
439
|
@__async_initialized__ = true
|
440
440
|
@__async_delegator__ = AsyncDelegator.new(self)
|
441
441
|
@__await_delegator__ = AwaitDelegator.new(@__async_delegator__)
|
data/lib/concurrent/atom.rb
CHANGED
@@ -3,7 +3,7 @@ require 'concurrent/collection/copy_on_notify_observer_set'
|
|
3
3
|
require 'concurrent/concern/observable'
|
4
4
|
require 'concurrent/synchronization'
|
5
5
|
|
6
|
-
# @!macro
|
6
|
+
# @!macro thread_safe_variable_comparison
|
7
7
|
#
|
8
8
|
# ## Thread-safe Variable Classes
|
9
9
|
#
|
@@ -96,8 +96,15 @@ module Concurrent
|
|
96
96
|
include Concern::Observable
|
97
97
|
|
98
98
|
safe_initialization!
|
99
|
-
|
99
|
+
attr_atomic(:value)
|
100
|
+
private :value=, :swap_value, :compare_and_set_value, :update_value
|
100
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.
|
101
108
|
|
102
109
|
# Create a new atom with the given initial value.
|
103
110
|
#
|
@@ -118,13 +125,6 @@ module Concurrent
|
|
118
125
|
self.value = value
|
119
126
|
end
|
120
127
|
|
121
|
-
# @!method value
|
122
|
-
# The current value of the atom.
|
123
|
-
#
|
124
|
-
# @return [Object] The current value.
|
125
|
-
|
126
|
-
alias_method :deref, :value
|
127
|
-
|
128
128
|
# Atomically swaps the value of atom using the given block. The current
|
129
129
|
# value will be passed to the block, as will any arguments passed as
|
130
130
|
# arguments to the function. The new value will be validated against the
|
@@ -5,19 +5,19 @@ module Concurrent
|
|
5
5
|
|
6
6
|
###################################################################
|
7
7
|
|
8
|
-
# @!macro
|
8
|
+
# @!macro atomic_boolean_method_initialize
|
9
9
|
#
|
10
10
|
# Creates a new `AtomicBoolean` with the given initial value.
|
11
11
|
#
|
12
12
|
# @param [Boolean] initial the initial value
|
13
13
|
|
14
|
-
# @!macro
|
14
|
+
# @!macro atomic_boolean_method_value_get
|
15
15
|
#
|
16
16
|
# Retrieves the current `Boolean` value.
|
17
17
|
#
|
18
18
|
# @return [Boolean] the current value
|
19
19
|
|
20
|
-
# @!macro
|
20
|
+
# @!macro atomic_boolean_method_value_set
|
21
21
|
#
|
22
22
|
# Explicitly sets the value.
|
23
23
|
#
|
@@ -25,25 +25,25 @@ module Concurrent
|
|
25
25
|
#
|
26
26
|
# @return [Boolean] the current value
|
27
27
|
|
28
|
-
# @!macro
|
28
|
+
# @!macro atomic_boolean_method_true_question
|
29
29
|
#
|
30
30
|
# Is the current value `true`
|
31
31
|
#
|
32
32
|
# @return [Boolean] true if the current value is `true`, else false
|
33
33
|
|
34
|
-
# @!macro
|
34
|
+
# @!macro atomic_boolean_method_false_question
|
35
35
|
#
|
36
36
|
# Is the current value `false`
|
37
37
|
#
|
38
38
|
# @return [Boolean] true if the current value is `false`, else false
|
39
39
|
|
40
|
-
# @!macro
|
40
|
+
# @!macro atomic_boolean_method_make_true
|
41
41
|
#
|
42
42
|
# Explicitly sets the value to true.
|
43
43
|
#
|
44
44
|
# @return [Boolean] true is value has changed, otherwise false
|
45
45
|
|
46
|
-
# @!macro
|
46
|
+
# @!macro atomic_boolean_method_make_false
|
47
47
|
#
|
48
48
|
# Explicitly sets the value to false.
|
49
49
|
#
|
@@ -51,7 +51,7 @@ module Concurrent
|
|
51
51
|
|
52
52
|
###################################################################
|
53
53
|
|
54
|
-
# @!macro
|
54
|
+
# @!macro atomic_boolean_public_api
|
55
55
|
#
|
56
56
|
# @!method initialize(initial = false)
|
57
57
|
# @!macro atomic_boolean_method_initialize
|
@@ -88,7 +88,7 @@ module Concurrent
|
|
88
88
|
end
|
89
89
|
private_constant :AtomicBooleanImplementation
|
90
90
|
|
91
|
-
# @!macro
|
91
|
+
# @!macro atomic_boolean
|
92
92
|
#
|
93
93
|
# A boolean value that can be updated atomically. Reads and writes to an atomic
|
94
94
|
# boolean and thread-safe and guaranteed to succeed. Reads and writes may block
|
@@ -96,17 +96,21 @@ module Concurrent
|
|
96
96
|
#
|
97
97
|
# @!macro thread_safe_variable_comparison
|
98
98
|
#
|
99
|
-
#
|
100
|
-
#
|
101
|
-
#
|
102
|
-
#
|
103
|
-
#
|
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)
|
104
107
|
#
|
105
|
-
#
|
106
|
-
#
|
107
|
-
#
|
108
|
-
#
|
109
|
-
#
|
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
|
+
# ```
|
110
114
|
#
|
111
115
|
# @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicBoolean.html java.util.concurrent.atomic.AtomicBoolean
|
112
116
|
#
|
@@ -114,7 +118,7 @@ module Concurrent
|
|
114
118
|
class AtomicBoolean < AtomicBooleanImplementation
|
115
119
|
# @return [String] Short string representation.
|
116
120
|
def to_s
|
117
|
-
format '
|
121
|
+
format '%s value:%s>', super[0..-2], value
|
118
122
|
end
|
119
123
|
|
120
124
|
alias_method :inspect, :to_s
|
@@ -5,20 +5,20 @@ module Concurrent
|
|
5
5
|
|
6
6
|
###################################################################
|
7
7
|
|
8
|
-
# @!macro
|
8
|
+
# @!macro atomic_fixnum_method_initialize
|
9
9
|
#
|
10
10
|
# Creates a new `AtomicFixnum` with the given initial value.
|
11
11
|
#
|
12
12
|
# @param [Fixnum] initial the initial value
|
13
13
|
# @raise [ArgumentError] if the initial value is not a `Fixnum`
|
14
14
|
|
15
|
-
# @!macro
|
15
|
+
# @!macro atomic_fixnum_method_value_get
|
16
16
|
#
|
17
17
|
# Retrieves the current `Fixnum` value.
|
18
18
|
#
|
19
19
|
# @return [Fixnum] the current value
|
20
20
|
|
21
|
-
# @!macro
|
21
|
+
# @!macro atomic_fixnum_method_value_set
|
22
22
|
#
|
23
23
|
# Explicitly sets the value.
|
24
24
|
#
|
@@ -28,7 +28,7 @@ module Concurrent
|
|
28
28
|
#
|
29
29
|
# @raise [ArgumentError] if the new value is not a `Fixnum`
|
30
30
|
|
31
|
-
# @!macro
|
31
|
+
# @!macro atomic_fixnum_method_increment
|
32
32
|
#
|
33
33
|
# Increases the current value by the given amount (defaults to 1).
|
34
34
|
#
|
@@ -36,7 +36,7 @@ module Concurrent
|
|
36
36
|
#
|
37
37
|
# @return [Fixnum] the current value after incrementation
|
38
38
|
|
39
|
-
# @!macro
|
39
|
+
# @!macro atomic_fixnum_method_decrement
|
40
40
|
#
|
41
41
|
# Decreases the current value by the given amount (defaults to 1).
|
42
42
|
#
|
@@ -44,7 +44,7 @@ module Concurrent
|
|
44
44
|
#
|
45
45
|
# @return [Fixnum] the current value after decrementation
|
46
46
|
|
47
|
-
# @!macro
|
47
|
+
# @!macro atomic_fixnum_method_compare_and_set
|
48
48
|
#
|
49
49
|
# Atomically sets the value to the given updated value if the current
|
50
50
|
# value == the expected value.
|
@@ -52,9 +52,9 @@ module Concurrent
|
|
52
52
|
# @param [Fixnum] expect the expected value
|
53
53
|
# @param [Fixnum] update the new value
|
54
54
|
#
|
55
|
-
# @return [
|
55
|
+
# @return [Boolean] true if the value was updated else false
|
56
56
|
|
57
|
-
# @!macro
|
57
|
+
# @!macro atomic_fixnum_method_update
|
58
58
|
#
|
59
59
|
# Pass the current value to the given block, replacing it
|
60
60
|
# with the block's result. May retry if the value changes
|
@@ -68,7 +68,7 @@ module Concurrent
|
|
68
68
|
|
69
69
|
###################################################################
|
70
70
|
|
71
|
-
# @!macro
|
71
|
+
# @!macro atomic_fixnum_public_api
|
72
72
|
#
|
73
73
|
# @!method initialize(initial = 0)
|
74
74
|
# @!macro atomic_fixnum_method_initialize
|
@@ -79,10 +79,10 @@ module Concurrent
|
|
79
79
|
# @!method value=(value)
|
80
80
|
# @!macro atomic_fixnum_method_value_set
|
81
81
|
#
|
82
|
-
# @!method increment
|
82
|
+
# @!method increment(delta)
|
83
83
|
# @!macro atomic_fixnum_method_increment
|
84
84
|
#
|
85
|
-
# @!method decrement
|
85
|
+
# @!method decrement(delta)
|
86
86
|
# @!macro atomic_fixnum_method_decrement
|
87
87
|
#
|
88
88
|
# @!method compare_and_set(expect, update)
|
@@ -105,7 +105,7 @@ module Concurrent
|
|
105
105
|
end
|
106
106
|
private_constant :AtomicFixnumImplementation
|
107
107
|
|
108
|
-
# @!macro
|
108
|
+
# @!macro atomic_fixnum
|
109
109
|
#
|
110
110
|
# A numeric value that can be updated atomically. Reads and writes to an atomic
|
111
111
|
# fixnum and thread-safe and guaranteed to succeed. Reads and writes may block
|
@@ -113,17 +113,21 @@ module Concurrent
|
|
113
113
|
#
|
114
114
|
# @!macro thread_safe_variable_comparison
|
115
115
|
#
|
116
|
-
#
|
117
|
-
#
|
118
|
-
#
|
119
|
-
#
|
120
|
-
#
|
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)
|
121
124
|
#
|
122
|
-
#
|
123
|
-
#
|
124
|
-
#
|
125
|
-
#
|
126
|
-
#
|
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
|
+
# ```
|
127
131
|
#
|
128
132
|
# @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicLong.html java.util.concurrent.atomic.AtomicLong
|
129
133
|
#
|
@@ -131,7 +135,7 @@ module Concurrent
|
|
131
135
|
class AtomicFixnum < AtomicFixnumImplementation
|
132
136
|
# @return [String] Short string representation.
|
133
137
|
def to_s
|
134
|
-
format '
|
138
|
+
format '%s value:%s>', super[0..-2], value
|
135
139
|
end
|
136
140
|
|
137
141
|
alias_method :inspect, :to_s
|
@@ -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
|