Class: Concurrent::Edge::AtomicMarkableReference — Concurrent

Class List Method List File List

# Class: Concurrent::Edge::AtomicMarkableReference

Inherits:
  Synchronization::Object
  - Object
  - Synchronization::Object
  - Concurrent::Edge::AtomicMarkableReference
  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.

See Also:

- java.util.concurrent.atomic.AtomicMarkableReference

## Defined Under Namespace

Classes: ImmutableArray

## Instance Method Summary (collapse)

- - (Boolean) compare_and_set(expected_val, new_val, expected_mark, new_mark) (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.

- - (ImmutableArray) get

  Gets the current reference and marked values.

- - (AtomicMarkableReference) initialize(value = nil, mark = false) constructor

  A new instance of AtomicMarkableReference.

- - (Boolean) mark (also: #marked?)

  Gets the current marked value.

- - (ImmutableArray) set(new_val, new_mark)

  Unconditionally sets to the given value of both the reference and the mark.

- - (ImmutableArray) try_update {|Object| ... }

  Pass the current value to the given block, replacing it with the block's result.

- - (ImmutableArray) try_update! {|Object| ... }

  Pass the current value to the given block, replacing it with the block's result.

- - (ImmutableArray) update {|Object| ... }

  Pass the current value and marked state to the given block, replacing it with the block's results.

- - (Object) value

  Gets the current value of the reference.

## Constructor Details

### - (`AtomicMarkableReference`) initialize(value = nil, mark = false)

Returns a new instance of AtomicMarkableReference

    16
    17
    18
    19
    # File 'lib/concurrent/edge/atomic_markable_reference.rb', line 16

    def initialize(value = nil, mark = false)
      super()
      self.reference = ImmutableArray[value, mark]
    end

## Instance Method Details

### - (`Boolean`) compare_and_set(expected_val, new_val, expected_mark, new_mark) 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

    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    # File 'lib/concurrent/edge/atomic_markable_reference.rb', line 36

    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

### - (`ImmutableArray`) get

Gets the current reference and marked values.

Returns:

- (`ImmutableArray`) —

  the current reference and marked values

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

    def get
      reference
    end

### - (`Boolean`) mark Also known as: marked?

Gets the current marked value

Returns:

- (`Boolean`) —

  the current marked value

    86
    87
    88
    # File 'lib/concurrent/edge/atomic_markable_reference.rb', line 86

    def mark
      reference[1]
    end

### - (`ImmutableArray`) set(new_val, new_mark)

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:

- (`ImmutableArray`) —

  both the new value and the new mark

    100
    101
    102
    # File 'lib/concurrent/edge/atomic_markable_reference.rb', line 100

    def set(new_val, new_mark)
      self.reference = ImmutableArray[new_val, new_mark]
    end

### - (`ImmutableArray`) try_update {|Object| ... }

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:

- (`ImmutableArray`) —

  the new value and marked state, or nil if

    167
    168
    169
    170
    171
    172
    173
    174
    # File 'lib/concurrent/edge/atomic_markable_reference.rb', line 167

    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

### - (`ImmutableArray`) try_update! {|Object| ... }

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:

- (`ImmutableArray`) —

  the new value and marked state

Raises:

- (`Concurrent::ConcurrentUpdateError`) —

  if the update fails

    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    # File 'lib/concurrent/edge/atomic_markable_reference.rb', line 141

    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

### - (`ImmutableArray`) update {|Object| ... }

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:

- (`ImmutableArray`) —

  the new value and new mark

    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    # File 'lib/concurrent/edge/atomic_markable_reference.rb', line 116

    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

### - (`Object`) value

Gets the current value of the reference

Returns:

- (`Object`) —

  the current value of the reference

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

    def value
      reference[0]
    end