A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from http://ruby-concurrency.github.io/concurrent-ruby/master/Concurrent/Atom.html below:

Class: Concurrent::Atom — Concurrent Ruby

Class: Concurrent::Atom
Inherits:
Synchronization::Object show all
Includes:
Concern::Observable
Defined in:
lib/concurrent-ruby/concurrent/atom.rb
Overview

Atoms provide a way to manage shared, synchronous, independent state.

An atom is initialized with an initial value and an optional validation proc. At any time the value of the atom can be synchronously and safely changed. If a validator is given at construction then any new value will be checked against the validator and will be rejected if the validator returns false or raises an exception.

There are two ways to change the value of an atom: #compare_and_set and #swap. The former will set the new value if and only if it validates and the current value matches the new value. The latter will atomically set the new value to the result of running the given block if and only if that value validates.

Example
def next_fibonacci(set = nil)
  return [0, 1] if set.nil?
  set + [set[-2..-1].reduce{|sum,x| sum + x }]
end

atom = Concurrent::Atom.new(next_fibonacci)

5.times do
  atom.swap{|set| next_fibonacci(set) }
end

atom.value 
Observation

Atoms support observers through the Observable mixin module. Notification of observers occurs every time the value of the Atom changes. When notified the observer will receive three arguments: time, old_value, and new_value. The time argument is the time at which the value change occurred. The old_value is the value of the Atom when the change began The new_value is the value to which the Atom was set when the change completed. Note that old_value and new_value may be the same. This is not an error. It simply means that the change operation returned the same value.

Unlike in Clojure, Atom cannot participate in TVar transactions.

Thread-safe Variable Classes

Each of the thread-safe variable classes is designed to solve a different problem. In general:

Instance Method Summary collapse Constructor Details #initialize(value, opts = {}) ⇒ Atom

Create a new atom with the given initial value.

121
122
123
124
125
126
# File 'lib/concurrent-ruby/concurrent/atom.rb', line 121

def initialize(value, opts = {})
  super()
  @Validator     = opts.fetch(:validator, -> v { true })
  self.observers = Collection::CopyOnNotifyObserverSet.new
  self.value     = value
end
Instance Method Details #compare_and_set(old_value, new_value) ⇒ Boolean

Atomically sets the value of atom to the new value if and only if the current value of the atom is identical to the old value and the new value successfully validates against the (optional) validator given at construction.

181
182
183
184
185
186
187
188
# File 'lib/concurrent-ruby/concurrent/atom.rb', line 181

def compare_and_set(old_value, new_value)
  if valid?(new_value) && compare_and_set_value(old_value, new_value)
    observers.notify_observers(Time.now, old_value, new_value)
    true
  else
    false
  end
end
#reset(new_value) ⇒ Object

Atomically sets the value of atom to the new value without regard for the current value so long as the new value successfully validates against the (optional) validator given at construction.

198
199
200
201
202
203
204
205
206
207
# File 'lib/concurrent-ruby/concurrent/atom.rb', line 198

def reset(new_value)
  old_value = value
  if valid?(new_value)
    self.value = new_value
    observers.notify_observers(Time.now, old_value, new_value)
    new_value
  else
    old_value
  end
end
#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.

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

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

  loop do
    old_value = value
    new_value = yield(old_value, *args)
    begin
      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
#value ⇒ Object Also known as: deref

The current value of the atom.


# File 'lib/concurrent-ruby/concurrent/atom.rb', line 104

#add_observer(observer = nil, func = :update, &block) ⇒ Object Originally defined in module Concern::Observable

Adds an observer to this set. If a block is passed, the observer will be created by this method and no other params should be passed.

#count_observers ⇒ Integer Originally defined in module Concern::Observable

Return the number of observers associated with this object.

#delete_observer(observer) ⇒ Object Originally defined in module Concern::Observable

Remove observer as an observer on this object so that it will no longer receive notifications.

#with_observer(observer = nil, func = :update, &block) ⇒ Observable Originally defined in module Concern::Observable

As #add_observer but can be used for chaining.


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4