class Concurrent::Synchronization::Object
Abstract object providing final, volatile, ans CAS extensions to build other concurrent abstractions.
-
final instance variables see {Object.safe_initialization!}
-
volatile instance variables see {Object.attr_volatile}
-
volatile instance variables see {Object.attr_atomic}
@!visibility private
Public Class Methods
@return [true, false] is the attribute with name atomic?
# File lib/concurrent-ruby/concurrent/synchronization/object.rb, line 125 def self.atomic_attribute?(name) atomic_attributes.include? name end
@param [true, false] inherited should inherited volatile with CAS fields be returned? @return [::Array<Symbol>] Returns defined volatile with CAS fields on this class.
# File lib/concurrent-ruby/concurrent/synchronization/object.rb, line 119 def self.atomic_attributes(inherited = true) @__atomic_fields__ ||= [] ((superclass.atomic_attributes if superclass.respond_to?(:atomic_attributes) && inherited) || []) + @__atomic_fields__ end
Creates methods for reading and writing to a instance variable with volatile (Java) semantic as {.attr_volatile} does. The instance variable should be accessed oly through generated methods. This method generates following methods: ‘value`, `value=(new_value) #=> new_value`, `swap_value(new_value) #=> old_value`, `compare_and_set_value(expected, value) #=> true || false`, `update_value(&block)`. @param [::Array<Symbol>] names of the instance variables to be volatile with CAS. @return [::Array<Symbol>] names of defined method names. @!macro attr_atomic
@!method $1 @return [Object] The $1. @!method $1=(new_$1) Set the $1. @return [Object] new_$1. @!method swap_$1(new_$1) Set the $1 to new_$1 and return the old $1. @return [Object] old $1 @!method compare_and_set_$1(expected_$1, new_$1) Sets the $1 to new_$1 if the current $1 is expected_$1 @return [true, false] @!method update_$1(&block) Updates the $1 using the block. @yield [Object] Calculate a new $1 using given (old) $1 @yieldparam [Object] old $1 @return [Object] new $1
# File lib/concurrent-ruby/concurrent/synchronization/object.rb, line 84 def self.attr_atomic(*names) @__atomic_fields__ ||= [] @__atomic_fields__ += names safe_initialization! define_initialize_atomic_fields names.each do |name| ivar = :"@Atomic#{name.to_s.gsub(/(?:^|_)(.)/) { $1.upcase }}" class_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{name} #{ivar}.get end def #{name}=(value) #{ivar}.set value end def swap_#{name}(value) #{ivar}.swap value end def compare_and_set_#{name}(expected, value) #{ivar}.compare_and_set expected, value end def update_#{name}(&block) #{ivar}.update(&block) end RUBY end names.flat_map { |n| [n, :"#{n}=", :"swap_#{n}", :"compare_and_set_#{n}", :"update_#{n}"] } end
For testing purposes, quite slow. Injects assert code to new method which will raise if class instance contains any instance variables with CamelCase names and isn’t {.safe_initialization?}. @raise when offend found @return [true]
# File lib/concurrent-ruby/concurrent/synchronization/object.rb, line 45 def self.ensure_safe_initialization_when_final_fields_are_present Object.class_eval do def self.new(*args, &block) object = super(*args, &block) ensure has_final_field = object.instance_variables.any? { |v| v.to_s =~ /^@[A-Z]/ } if has_final_field && !safe_initialization? raise "there was an instance of #{object.class} with final field but not marked with safe_initialization!" end end end true end
Has to be called by children.
Concurrent::Synchronization::AbstractObject::new
# File lib/concurrent-ruby/concurrent/synchronization/object.rb, line 28 def initialize super __initialize_atomic_fields__ end
Concurrent::Synchronization::AbstractObject::new
# File lib/concurrent-ruby/concurrent/synchronization/object.rb, line 47 def self.new(*args, &block) object = super(*args, &block) ensure has_final_field = object.instance_variables.any? { |v| v.to_s =~ /^@[A-Z]/ } if has_final_field && !safe_initialization? raise "there was an instance of #{object.class} with final field but not marked with safe_initialization!" end end
# File lib/concurrent-ruby/concurrent/synchronization/object.rb, line 33 def self.safe_initialization! extend SafeInitialization unless safe_initialization? end
# File lib/concurrent-ruby/concurrent/synchronization/object.rb, line 37 def self.safe_initialization? self.singleton_class < SafeInitialization end
Private Class Methods
# File lib/concurrent-ruby/concurrent/synchronization/object.rb, line 131 def self.define_initialize_atomic_fields assignments = @__atomic_fields__.map do |name| "@Atomic#{name.to_s.gsub(/(?:^|_)(.)/) { $1.upcase }} = Concurrent::AtomicReference.new(nil)" end.join("\n") class_eval <<-RUBY, __FILE__, __LINE__ + 1 def __initialize_atomic_fields__ super #{assignments} end RUBY end
Private Instance Methods
# File lib/concurrent-ruby/concurrent/synchronization/object.rb, line 146 def __initialize_atomic_fields__ end