# class Sync::Shared(T)

- Sync::Shared(T)
- Reference
- Object

##
Overview

Safely share a value `T` across fibers and execution contexts using a `RWLock` to control when the access to a value can be shared (read-only) or must be exclusive (replace or mutate the value).

For example:

    require "sync/shared"

    class Queue
      @@running : Sync::Shared.new([] of Queue)

      def self.on_started(queue)
        @@running.lock(&.push(queue))
      end

      def self.on_stopped(queue)
        @@running.lock(&.delete(queue))
      end

      def self.each(&)
        @@running.shared do |list|
          list.each { |queue| yield queue }
        end
      end
    end

Consider a `Shared(T)` if your workload mostly consists of immutable reads of the value, with only seldom writes or inner mutations of the value's inner state.

##
Included Modules

- Sync::Lockable

##
Defined in:

sync/shared.cr

##
Constructors

- .new(value : T, type : Type = :checked)

##
Instance Method Summary

- #get : T

  Locks in shared mode and returns the value.

- #lock(& : T -> _)

  Locks in exclusive mode and yields the value.

- #replace(& : T -> T) : Nil

  Locks in exclusive mode, yields the current value and eventually replaces the value with the one returned by the block.

- #set(value : T) : Nil

  Locks in exclusive mode and sets the value.

- #shared(& : T -> _)

  Locks in shared mode and yields the value.

- #unsafe_get : T

  Returns the value without any synchronization.

- #unsafe_set(value : T) : T

  Sets the value without any synchronization.

### Instance methods inherited from class `Reference`

==(other : self)
==(other : JSON::Any)
==(other : YAML::Any)
==(other) ==, dup dup, hash(hasher) hash, initialize initialize, inspect(io : IO) : Nil inspect, object_id : UInt64 object_id, pretty_print(pp) : Nil pretty_print, same?(other : Reference) : Bool
same?(other : Nil) same?, to_s(io : IO) : Nil to_s

### Constructor methods inherited from class `Reference`

new new, unsafe_construct(address : Pointer, *args, **opts) : self unsafe_construct

### Class methods inherited from class `Reference`

pre_initialize(address : Pointer) pre_initialize

### Instance methods inherited from class `Object`

! : Bool !, !=(other) !=, !~(other) !~, ==(other) ==, ===(other : JSON::Any)
===(other : YAML::Any)
===(other) ===, =~(other) =~, as(type : Class) as, as?(type : Class) as?, class class, dup dup, hash(hasher)
hash hash, in?(collection : Object) : Bool
in?(*values : Object) : Bool in?, inspect(io : IO) : Nil
inspect : String inspect, is_a?(type : Class) : Bool is_a?, itself itself, nil? : Bool nil?, not_nil!(message)
not_nil! not_nil!, pretty_inspect(width = 79, newline = "\n", indent = 0) : String pretty_inspect, pretty_print(pp : PrettyPrint) : Nil pretty_print, responds_to?(name : Symbol) : Bool responds_to?, tap(&) tap, to_json(io : IO) : Nil
to_json : String to_json, to_pretty_json(indent : String = " ") : String
to_pretty_json(io : IO, indent : String = " ") : Nil to_pretty_json, to_s(io : IO) : Nil
to_s : String to_s, to_yaml(io : IO) : Nil
to_yaml : String to_yaml, try(&) try, unsafe_as(type : T.class) forall T unsafe_as

### Class methods inherited from class `Object`

from_json(string_or_io : String | IO, root : String)
from_json(string_or_io : String | IO) from_json, from_yaml(string_or_io : String | IO) from_yaml

### Macros inherited from class `Object`

class_getter(*names, &block) class_getter, class_getter!(*names) class_getter!, class_getter?(*names, &block) class_getter?, class_property(*names, &block) class_property, class_property!(*names) class_property!, class_property?(*names, &block) class_property?, class_setter(*names) class_setter, def_clone def_clone, def_equals(*fields) def_equals, def_equals_and_hash(*fields) def_equals_and_hash, def_hash(*fields) def_hash, delegate(*methods, to object) delegate, forward_missing_to(delegate) forward_missing_to, getter(*names, &block) getter, getter!(*names) getter!, getter?(*names, &block) getter?, property(*names, &block) property, property!(*names) property!, property?(*names, &block) property?, setter(*names) setter

##
Constructor Detail

def self.new(value : T, type : Type = :checked) #

##
Instance Method Detail

def get : T #

Locks in shared mode and returns the value. Unlocks before returning.

Always acquires the lock, so reading the value is synchronized in relation with the other methods. However, safely accessing the returned value entirely depends on the safety of `T`.

Prefer `#shared(&.dup)` or `#shared(&.clone)` to get a shallow or deep copy of the value instead.

WARNING Breaks the shared/exclusive guarantees since the returned value outlives the lock, the value can be accessed concurrently to the synchronized methods.

def lock(& : T -> _) #

Locks in exclusive mode and yields the value. The lock is released before returning.

The value is owned in exclusive mode for the duration of the block, as such it can be safely mutated.

WARNING The value musn't be retained and accessed after the block has returned.

def replace(& : T -> T) : Nil #

Locks in exclusive mode, yields the current value and eventually replaces the value with the one returned by the block. The lock is released before returning.

The current value is now owned: it can be safely retained and mutated even after the block returned.

WARNING The new value musn't be retained and accessed after the block has returned.

def set(value : T) : Nil #

Locks in exclusive mode and sets the value.

def shared(& : T -> _) #

Locks in shared mode and yields the value. The lock is released before returning.

The value is owned in shared mode for the duration of the block, and thus shouldn't be mutated for example, unless `T` can be safely mutated (it should be `Sync::Safe`).

WARNING The value musn't be retained and accessed after the block has returned.

def unsafe_get : T #

Returns the value without any synchronization.

WARNING Breaks the safety constraints! Should only be called after acquiring the exclusive lock.

def unsafe_set(value : T) : T #

Sets the value without any synchronization.

WARNING Breaks the safety constraints! Should only be called after acquiring the exclusive lock.