Method: Concurrent::Atom#swap

Defined in:
lib/concurrent/atom.rb

#swap(*args) {|value, args| ... } ⇒ Object

Note:

The given block may be called multiple times, and thus should be free of side effects.

Atomically swaps the value of atom using the given block. The current value will be passed to the block, as will any arguments passed as arguments to the function. The new value will be validated against the (optional) validator proc given at construction. If validation fails the value will not be changed.

Internally, #swap reads the current value, applies the block to it, and attempts to compare-and-set it in. Since another thread may have changed the value in the intervening time, it may have to retry, and does so in a spin loop. The net effect is that the value will always be the result of the application of the supplied block to a current value, atomically. However, because the block might be called multiple times, it must be free of side effects.

Parameters:

  • args (Object)

    Zero or more arguments passed to the block.

Yields:

  • (value, args)

    Calculates a new value for the atom based on the current value and any supplied agruments.

Yield Parameters:

  • value (Object)

    The current value of the atom.

  • args (Object)

    All arguments passed to the function, in order.

Yield Returns:

  • (Object)

    The intended new value of the atom.

Returns:

  • (Object)

    The final value of the atom after all operations and validations are complete.

Raises:

  • (ArgumentError)

    When no block is given.



156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/concurrent/atom.rb', line 156

def swap(*args)
  raise ArgumentError.new('no block given') unless block_given?

  loop do
    old_value = value
    begin
      new_value = yield(old_value, *args)
      break old_value unless valid?(new_value)
      break new_value if compare_and_set(old_value, new_value)
    rescue
      break old_value
    end
  end
end