Class: Concurrent::Edge::AtomicMarkableReference
- Inherits:
-
Synchronization::Object
- Object
- Synchronization::Object
- Concurrent::Edge::AtomicMarkableReference
- Defined in:
- lib/concurrent/edge/atomic_markable_reference.rb
Overview
An atomic reference which maintains an object reference along with a mark bit that can be updated atomically.
Defined Under Namespace
Classes: ImmutableArray
Instance Method Summary collapse
-
#compare_and_set(expected_val, new_val, expected_mark, new_mark) ⇒ Boolean
(also: #compare_and_swap)
Atomically sets the value and mark to the given updated value and mark given both: - the current value == the expected value && - the current mark == the expected mark.
-
#get ⇒ ImmutableArray
Gets the current reference and marked values.
-
#initialize(value = nil, mark = false) ⇒ AtomicMarkableReference
constructor
A new instance of AtomicMarkableReference.
-
#mark ⇒ Boolean
(also: #marked?)
Gets the current marked value.
-
#set(new_val, new_mark) ⇒ ImmutableArray
Unconditionally sets to the given value of both the reference and the mark.
-
#try_update {|Object| ... } ⇒ ImmutableArray
Pass the current value to the given block, replacing it with the block’s result.
-
#try_update! {|Object| ... } ⇒ ImmutableArray
Pass the current value to the given block, replacing it with the block’s result.
-
#update {|Object| ... } ⇒ ImmutableArray
Pass the current value and marked state to the given block, replacing it with the block’s results.
-
#value ⇒ Object
Gets the current value of the reference.
Constructor Details
#initialize(value = nil, mark = false) ⇒ AtomicMarkableReference
Returns a new instance of AtomicMarkableReference.
17 18 19 20 |
# File 'lib/concurrent/edge/atomic_markable_reference.rb', line 17 def initialize(value = nil, mark = false) super() self.reference = ImmutableArray[value, mark] end |
Instance Method Details
#compare_and_set(expected_val, new_val, expected_mark, new_mark) ⇒ Boolean Also known as: compare_and_swap
Atomically sets the value and mark to the given updated value and mark given both:
- the current value == the expected value &&
- the current mark == the expected mark
that the actual value was not equal to the expected value or the actual mark was not equal to the expected mark
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/concurrent/edge/atomic_markable_reference.rb', line 37 def compare_and_set(expected_val, new_val, expected_mark, new_mark) # Memoize a valid reference to the current AtomicReference for # later comparison. current = reference curr_val, curr_mark = current # Ensure that that the expected marks match. return false unless expected_mark == curr_mark if expected_val.is_a? Numeric # If the object is a numeric, we need to ensure we are comparing # the numerical values return false unless expected_val == curr_val else # Otherwise, we need to ensure we are comparing the object identity. # Theoretically, this could be incorrect if a user monkey-patched # `Object#equal?`, but they should know that they are playing with # fire at that point. return false unless expected_val.equal? curr_val end prospect = ImmutableArray[new_val, new_mark] compare_and_set_reference current, prospect end |
#get ⇒ ImmutableArray
Gets the current reference and marked values.
69 70 71 |
# File 'lib/concurrent/edge/atomic_markable_reference.rb', line 69 def get reference end |
#mark ⇒ Boolean Also known as: marked?
Gets the current marked value
87 88 89 |
# File 'lib/concurrent/edge/atomic_markable_reference.rb', line 87 def mark reference[1] end |
#set(new_val, new_mark) ⇒ ImmutableArray
Unconditionally sets to the given value of both the reference and the mark.
101 102 103 |
# File 'lib/concurrent/edge/atomic_markable_reference.rb', line 101 def set(new_val, new_mark) self.reference = ImmutableArray[new_val, new_mark] end |
#try_update {|Object| ... } ⇒ ImmutableArray
Pass the current value to the given block, replacing it with the block’s result. Simply return nil if update fails.
the update failed
168 169 170 171 172 173 174 175 |
# File 'lib/concurrent/edge/atomic_markable_reference.rb', line 168 def try_update old_val, old_mark = reference new_val, new_mark = yield old_val, old_mark return unless compare_and_set old_val, new_val, old_mark, new_mark ImmutableArray[new_val, new_mark] end |
#try_update! {|Object| ... } ⇒ ImmutableArray
Pass the current value to the given block, replacing it with the block’s result. Raise an exception if the update fails.
142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/concurrent/edge/atomic_markable_reference.rb', line 142 def try_update! old_val, old_mark = reference new_val, new_mark = yield old_val, old_mark unless compare_and_set old_val, new_val, old_mark, new_mark fail ::Concurrent::ConcurrentUpdateError, 'AtomicMarkableReference: Update failed due to race condition.', 'Note: If you would like to guarantee an update, please use ' \ 'the `AtomicMarkableReference#update` method.' end ImmutableArray[new_val, new_mark] end |
#update {|Object| ... } ⇒ ImmutableArray
Pass the current value and marked state to the given block, replacing it with the block’s results. May retry if the value changes during the block’s execution.
117 118 119 120 121 122 123 124 125 126 |
# File 'lib/concurrent/edge/atomic_markable_reference.rb', line 117 def update loop do old_val, old_mark = reference new_val, new_mark = yield old_val, old_mark if compare_and_set old_val, new_val, old_mark, new_mark return ImmutableArray[new_val, new_mark] end end end |
#value ⇒ Object
Gets the current value of the reference
78 79 80 |
# File 'lib/concurrent/edge/atomic_markable_reference.rb', line 78 def value reference[0] end |