# Class: Concurrent::Synchronization::Object

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

Defined in:
  lib/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, Cancellation::Token, Channel::Tick, Edge::LockFreeLinkedSet::Node, LazyRegister, LockFreeQueue::Node, LockFreeStack, MVar, Maybe, ProcessingActor, Promises::AbstractEventFuture, Promises::Channel, ReadWriteLock, ReentrantReadWriteLock, TVar, Throttle

## Class Method Summary collapse

- .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 ⇒ undocumented

  For testing purposes, quite slow.

- .new(*args, &block) ⇒ undocumented
- .safe_initialization! ⇒ undocumented

  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.

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

  Returns defined volatile with CAS fields on this class.

## 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/synchronization/object.rb', line 36

    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.

    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
    124
    125

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

    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 28

### .ensure_safe_initialization_when_final_fields_are_present ⇒ `undocumented`

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

    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84

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

    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

### .new(*args, &block) ⇒ `undocumented`

    56
    57
    58
    59
    60

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

    def self.new(*args, &block)
      object = super(*args, &block)
    ensure
      object.full_memory_barrier if object
    end

### .safe_initialization! ⇒ `undocumented`

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

    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63

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

    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.

    66
    67
    68
    69

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

    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.

    129
    130
    131
    132
    133

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

    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