Class: Concurrent::Synchronization::Object — Concurrent Ruby

# Class: Concurrent::Synchronization::Object

Inherits:
  ObjectImplementation
  - Object
  - Concurrent::Synchronization::Object
  show all

Defined in:
  lib/concurrent-ruby/concurrent/synchronization/object.rb

## Overview

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

## Direct Known Subclasses

Atom, AtomicMarkableReference, Cancellation, Channel::Tick, Edge::LockFreeLinkedSet::Node, ErlangActor::Environment, ErlangActor::Pid, LazyRegister, LockFreeQueue::Node, LockFreeStack, MVar, Maybe, ProcessingActor, Promises::AbstractEventFuture, Promises::Channel, ReadWriteLock, ReentrantReadWriteLock, TVar, Throttle, WrappingExecutor

## Class Method Summary collapse

- .atomic_attribute?(name) ⇒ true, false

  Is the attribute with name atomic?.

- .atomic_attributes(inherited = true) ⇒ ::Array<Symbol>

  Returns defined volatile with CAS fields on this class.

- .attr_atomic(*names) ⇒ ::Array<Symbol>

  Creates methods for reading and writing to a instance variable with volatile (Java) semantic as Object.attr_volatile does.

- .attr_volatile(*names) ⇒ ::Array<Symbol>

  Creates methods for reading and writing (as `attr_accessor` does) to a instance variable with volatile (Java) semantic.

- .ensure_safe_initialization_when_final_fields_are_present ⇒ true

  For testing purposes, quite slow.

- .safe_initialization! ⇒ true

  By calling this method on a class, it and all its children are marked to be constructed safely.

- .safe_initialization? ⇒ true, false

  If this class is safely initialized.

## Instance Method Summary collapse

- #initialize ⇒ Object constructor

  Has to be called by children.

## Constructor Details

### #initialize ⇒ `Object`

Has to be called by children.

    36
    37
    38
    39
    # File 'lib/concurrent-ruby/concurrent/synchronization/object.rb', line 36

    def initialize
      super
      __initialize_atomic_fields__
    end

## Class Method Details

### .atomic_attribute?(name) ⇒ `true`, `false`

Returns is the attribute with name atomic?.

Returns:

- (`true`, `false`) —

  is the attribute with name atomic?

    157
    158
    159
    # File 'lib/concurrent-ruby/concurrent/synchronization/object.rb', line 157

    def self.atomic_attribute?(name)
      atomic_attributes.include? name
    end

### .atomic_attributes(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.

    151
    152
    153
    154
    # File 'lib/concurrent-ruby/concurrent/synchronization/object.rb', line 151

    def self.atomic_attributes(inherited = true)
      @__atomic_fields__ ||= []
      ((superclass.atomic_attributes if superclass.respond_to?(:atomic_attributes) && inherited) || []) + @__atomic_fields__
    end

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

    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    # File 'lib/concurrent-ruby/concurrent/synchronization/object.rb', line 116

    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

### .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 only 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-ruby/concurrent/synchronization/object.rb', line 28

### .ensure_safe_initialization_when_final_fields_are_present ⇒ `true`

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

Returns:

- (`true`)

Raises:

- when offend found

    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    # File 'lib/concurrent-ruby/concurrent/synchronization/object.rb', line 77

    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

### .safe_initialization! ⇒ `true`

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

Returns:

- (`true`)

    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    # File 'lib/concurrent-ruby/concurrent/synchronization/object.rb', line 53

    def self.safe_initialization!
      # define only once, and not again in children
      return if safe_initialization?

      # @!visibility private
      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.

    68
    69
    70
    71
    # File 'lib/concurrent-ruby/concurrent/synchronization/object.rb', line 68

    def self.safe_initialization?
      @safe_initialization = false unless defined? @safe_initialization
      @safe_initialization || (superclass.respond_to?(:safe_initialization?) && superclass.safe_initialization?)
    end