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}
Public Class Methods
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.
# File lib/concurrent/synchronization/object.rb, line 92 def self.attr_atomic(*names) @volatile_cas_fields ||= [] @volatile_cas_fields += names safe_initialization! define_initialize_volatile_with_cas names.each do |name| ivar = :"@Atomic#{name.to_s.gsub(/(?:^|_)(.)/) { $1.upcase }}" class_eval " 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 ", __FILE__, __LINE__ + 1 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?}.
# File lib/concurrent/synchronization/object.rb, line 71 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 end
Has to be called by children.
# File lib/concurrent/synchronization/object.rb, line 34 def initialize super initialize_volatile_with_cas end
# File lib/concurrent/synchronization/object.rb, line 54 def self.new(*args, &block) object = super(*args, &block) ensure object.full_memory_barrier if object end
By calling this method on a class, it and all its children are marked to be constructed safely. Meaning that all writes (ivar initializations) are made visible to all readers of newly constructed object. It ensures same behaviour as Java's final fields. @example
class AClass < Concurrent::Synchronization::Object safe_initialization! def initialize @AFinalValue = 'value' # published safely, does not have to be synchronized end end
# File lib/concurrent/synchronization/object.rb, line 50 def self.safe_initialization! # define only once, and not again in children return if safe_initialization? def self.new(*args, &block) object = super(*args, &block) ensure object.full_memory_barrier if object end @safe_initialization = true end
@return [true, false] if this class is safely initialized.
# File lib/concurrent/synchronization/object.rb, line 64 def self.safe_initialization? @safe_initialization = false unless defined? @safe_initialization @safe_initialization || (superclass.respond_to?(:safe_initialization?) && superclass.safe_initialization?) 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/synchronization/object.rb, line 127 def self.volatile_cas_fields(inherited = true) @volatile_cas_fields ||= [] ((superclass.volatile_cas_fields if superclass.respond_to?(:volatile_cas_fields) && inherited) || []) + @volatile_cas_fields end
Private Class Methods
# File lib/concurrent/synchronization/object.rb, line 135 def self.define_initialize_volatile_with_cas assignments = @volatile_cas_fields.map { |name| "@Atomic#{name.to_s.gsub(/(?:^|_)(.)/) { $1.upcase }} = AtomicReference.new(nil)" }.join("\n") class_eval <<-RUBY def initialize_volatile_with_cas super #{assignments} end RUBY end
Private Instance Methods
# File lib/concurrent/synchronization/object.rb, line 147 def initialize_volatile_with_cas end