Class: Concurrent::AtomicMarkableReference

Inherits:
Synchronization::Object
  • Object
show all
Defined in:
lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb

Overview

An atomic reference which maintains an object reference along with a mark bit that can be updated atomically.

Instance Method Summary collapse

Constructor Details

#initialize(value = nil, mark = false) ⇒ AtomicMarkableReference

Returns a new instance of AtomicMarkableReference.



15
16
17
18
# File 'lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb', line 15

def initialize(value = nil, mark = false)
  super()
  self.reference = immutable_array(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



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb', line 33

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 = immutable_array(new_val, new_mark)

  compare_and_set_reference current, prospect
end

#getArray

Gets the current reference and marked values.

Returns:

  • (Array)

    the current reference and marked values



64
65
66
# File 'lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb', line 64

def get
  reference
end

#markBoolean Also known as: marked?

Gets the current marked value

Returns:

  • (Boolean)

    the current marked value



78
79
80
# File 'lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb', line 78

def mark
  reference[1]
end

#set(new_val, new_mark) ⇒ Array

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:

  • (Array)

    both the new value and the new mark



91
92
93
# File 'lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb', line 91

def set(new_val, new_mark)
  self.reference = immutable_array(new_val, new_mark)
end

#try_update {|Object| ... } ⇒ Array

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:

  • (Array)

    the new value and marked state, or nil if



152
153
154
155
156
157
158
159
# File 'lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb', line 152

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

  immutable_array(new_val, new_mark)
end

#try_update! {|Object| ... } ⇒ Array

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:

  • (Array)

    the new value and marked state

Raises:



128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb', line 128

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

  immutable_array(new_val, new_mark)
end

#update {|Object| ... } ⇒ Array

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:

  • (Array)

    the new value and new mark



105
106
107
108
109
110
111
112
113
114
# File 'lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb', line 105

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 immutable_array(new_val, new_mark)
    end
  end
end

#valueObject

Gets the current value of the reference

Returns:

  • (Object)

    the current value of the reference



71
72
73
# File 'lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb', line 71

def value
  reference[0]
end