Class: Concurrent::Synchronization::Object

Inherits:
ObjectImplementation
  • Object
show all
Defined in:
lib/concurrent/synchronization/object.rb

Overview

Abstract object providing final, volatile, ans CAS extensions to build other concurrent abstractions.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeObject

Has to be called by children.



34
35
36
37
# File 'lib/concurrent/synchronization/object.rb', line 34

def initialize
  super
  initialize_volatile_with_cas
end

Class Method Details

.attr_atomic(*names) ⇒ Array<Symbol>

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)`.

Parameters:

  • names (Array<Symbol>)

    of the instance variables to be volatile with CAS.

Returns:

  • (Array<Symbol>)

    names of defined method names.



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# 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 <<-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

.attr_volatile(*names) ⇒ Array<Symbol>

Creates methods for reading and writing (as ‘attr_accessor` does) to a instance variable with volatile (Java) semantic. The instance variable should be accessed oly through generated methods.

Parameters:

  • names (Array<Symbol>)

    of the instance variables to be volatile

Returns:

  • (Array<Symbol>)

    names of defined method names



# File 'lib/concurrent/synchronization/object.rb', line 26

.ensure_safe_initialization_when_final_fields_are_presentObject

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?.



71
72
73
74
75
76
77
78
79
80
81
82
# 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(*)
      object = super
    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

.new(*args, &block) ⇒ Object



54
55
56
57
58
# 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

.safe_initialization!Object

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.

Examples:

class AClass < Concurrent::Synchronization::Object
  safe_initialization!

  def initialize
    @AFinalValue = 'value' # published safely, does not have to be synchronized
  end
end


50
51
52
53
54
55
56
57
58
59
60
61
# 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

.safe_initialization?true, false

Returns if this class is safely initialized.

Returns:

  • (true, false)

    if this class is safely initialized.



64
65
66
67
# 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

.volatile_cas_fields(inherited = true) ⇒ Array<Symbol>

Returns defined volatile with CAS fields on this class.

Parameters:

  • inherited (true, false) (defaults to: true)

    should inherited volatile with CAS fields be returned?

Returns:

  • (Array<Symbol>)

    Returns defined volatile with CAS fields on this class.



127
128
129
130
131
# 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