123456789_123456789_123456789_123456789_123456789_

Class: Concurrent::AtomicMarkableReference

Overview

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

Class Attribute Summary

Class Method Summary

Synchronization::Object - Inherited

.atomic_attribute?, .atomic_attributes,
.attr_atomic

Creates methods for reading and writing to a instance variable with volatile (Java) semantic as .attr_volatile does.

.attr_volatile

Creates methods for reading and writing (as attr_accessor does) to a instance variable with volatile (Java) semantic.

.ensure_safe_initialization_when_final_fields_are_present

For testing purposes, quite slow.

.new

Has to be called by children.

.safe_initialization!, .define_initialize_atomic_fields

Synchronization::AbstractObject - Inherited

Instance Attribute Summary

Instance Method Summary

Synchronization::Object - Inherited

Synchronization::Volatile - Included

Synchronization::AbstractObject - Inherited

Constructor Details

.new(value = nil, mark = false) ⇒ AtomicMarkableReference

[ GitHub ]

  
# 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 Attribute Details

#marked? (readonly)

Alias for #mark.

[ GitHub ]

  
# File 'lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb', line 82

alias_method :marked?, :mark

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

[ GitHub ]

  
# 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

#compare_and_set_reference(expected_reference, new_reference) ⇒ true, false (private)

Sets the reference to new_reference if the current reference is expected_reference

[ GitHub ]

  
# File 'lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb', line 12

attr_atomic(:reference)

#compare_and_swap(expected_val, new_val, expected_mark, new_mark)

Alias for #compare_and_set.

[ GitHub ]

  
# File 'lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb', line 59

alias_method :compare_and_swap, :compare_and_set

#getArray

Gets the current reference and marked values.

Returns:

  • (Array)

    the current reference and marked values

[ GitHub ]

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

def get
  reference
end

#immutable_array(*args) (private)

[ GitHub ]

  
# File 'lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb', line 163

def immutable_array(*args)
  args.freeze
end

#markBoolean Also known as: #marked?

Gets the current marked value

Returns:

  • (Boolean)

    the current marked value

[ GitHub ]

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

def mark
  reference[1]
end

#referenceObject (private)

Returns:

[ GitHub ]

  
# File 'lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb', line 12

attr_atomic(:reference)

#reference=(new_reference) ⇒ Object (private)

Set the reference.

Returns:

[ GitHub ]

  
# File 'lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb', line 12

attr_atomic(:reference)

#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

[ GitHub ]

  
# 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

#swap_reference(new_reference) ⇒ Object (private)

Set the reference to new_reference and return the old reference.

Returns:

[ GitHub ]

  
# File 'lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb', line 12

attr_atomic(:reference)

#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

[ GitHub ]

  
# 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:

[ GitHub ]

  
# 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

[ GitHub ]

  
# 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

#update_reference {|Object| ... } ⇒ Object (private)

Updates the reference using the block.

Yields:

  • (Object)

    Calculate a new reference using given (old) reference

Yield Parameters:

Returns:

[ GitHub ]

  
# File 'lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb', line 12

attr_atomic(:reference)

#valueObject

Gets the current value of the reference

Returns:

  • (Object)

    the current value of the reference

[ GitHub ]

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

def value
  reference[0]
end