Class: Concurrent::Edge::AtomicMarkableReference

Inherits:
Synchronization::Object
  • Object
show all
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

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

Parameters:

  • expected_val (Object)

    the expected value

  • new_val (Object)

    the new value

  • expected_mark (Boolean)

    the expected mark

  • new_mark (Boolean)

    the new mark

Returns:

  • (Boolean)

    ‘true` if successful. A `false` return indicates



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

#getImmutableArray

Gets the current reference and marked values.

Returns:



69
70
71
# File 'lib/concurrent/edge/atomic_markable_reference.rb', line 69

def get
  reference
end

#markBoolean Also known as: marked?

Gets the current marked value

Returns:

  • (Boolean)

    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.

Parameters:

  • new_val (Object)

    the new value

  • new_mark (Boolean)

    the new mark

Returns:



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

Yields:

  • (Object)

    Calculate a new value and marked state for the atomic reference using given (old) value and (old) marked

Yield Parameters:

  • old_val (Object)

    the starting value of the atomic reference

  • old_mark (Boolean)

    the starting state of marked

Returns:



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.

Yields:

  • (Object)

    Calculate a new value and marked state for the atomic reference using given (old) value and (old) marked

Yield Parameters:

  • old_val (Object)

    the starting value of the atomic reference

  • old_mark (Boolean)

    the starting state of marked

Returns:

Raises:

  • (Concurrent::ConcurrentUpdateError)

    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.

Yields:

  • (Object)

    Calculate a new value and marked state for the atomic reference using given (old) value and (old) marked

Yield Parameters:

  • old_val (Object)

    the starting value of the atomic reference

  • old_mark (Boolean)

    the starting state of marked

Returns:



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

#valueObject

Gets the current value of the reference

Returns:

  • (Object)

    the current value of the reference



78
79
80
# File 'lib/concurrent/edge/atomic_markable_reference.rb', line 78

def value
  reference[0]
end