123456789_123456789_123456789_123456789_123456789_

Class: Concurrent::FiberLocalVar

Relationships & Source Files
Inherits: Object
Defined in: lib/concurrent-ruby/concurrent/atomic/fiber_local_var.rb

Overview

A FiberLocalVar is a variable where the value is different for each fiber. Each variable may have a default value, but when you modify the variable only the current fiber will ever see that change.

This is similar to Ruby’s built-in fiber-local variables (‘Thread.current`), but with these major advantages:

  • FiberLocalVar has its own identity, it doesn’t need a Symbol.

  • Each Ruby’s built-in fiber-local variable leaks some memory forever (it’s a Symbol held forever on the fiber), so it’s only OK to create a small amount of them. FiberLocalVar has no such issue and it is fine to create many of them.

  • Ruby’s built-in fiber-local variables leak forever the value set on each fiber (unless set to nil explicitly). FiberLocalVar automatically removes the mapping for each fiber once the FiberLocalVar instance is GC’d.

Examples:

v = FiberLocalVar.new(14)
v.value #=> 14
v.value = 2
v.value #=> 2
v = FiberLocalVar.new(14)

Fiber.new do
  v.value #=> 14
  v.value = 1
  v.value #=> 1
end.resume

Fiber.new do
  v.value #=> 14
  v.value = 2
  v.value #=> 2
end.resume

v.value #=> 14

Constant Summary

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Constructor Details

.new(default = nil, &default_block) ⇒ FiberLocalVar

Creates a fiber local variable.

Parameters:

  • default (Object) (defaults to: nil)

    the default value when otherwise unset

  • default_block (Proc)

    Optional block that gets called to obtain the default value for each fiber

[ GitHub ]

  
# File 'lib/concurrent-ruby/concurrent/atomic/fiber_local_var.rb', line 49

def initialize(default = nil, &default_block)
  if default && block_given?
    raise ArgumentError, "Cannot use both value and block as default value"
  end

  if block_given?
    @default_block = default_block
    @default = nil
  else
    @default_block = nil
    @default = default
  end

  @index = LOCALS.next_index(self)
end

Instance Attribute Details

#valueObject (rw)

Returns the value in the current fiber’s copy of this fiber-local variable.

Returns:

  • (Object)

    the current value

[ GitHub ]

  
# File 'lib/concurrent-ruby/concurrent/atomic/fiber_local_var.rb', line 68

def value
  LOCALS.fetch(@index) { default }
end

#value=(value) ⇒ Object (rw)

Sets the current fiber’s copy of this fiber-local variable to the specified value.

Parameters:

  • value (Object)

    the value to set

Returns:

[ GitHub ]

  
# File 'lib/concurrent-ruby/concurrent/atomic/fiber_local_var.rb', line 76

def value=(value)
  LOCALS.set(@index, value)
end

Instance Method Details

#bind(value) { ... } ⇒ Object

Bind the given value to fiber local storage during execution of the given block.

Parameters:

  • value (Object)

    the value to bind

Yields:

  • the operation to be performed with the bound variable

Returns:

[ GitHub ]

  
# File 'lib/concurrent-ruby/concurrent/atomic/fiber_local_var.rb', line 86

def bind(value)
  if block_given?
    old_value = self.value
    self.value = value
    begin
      yield
    ensure
      self.value = old_value
    end
  end
end

#default (private)

[ GitHub ]

  
# File 'lib/concurrent-ruby/concurrent/atomic/fiber_local_var.rb', line 101

def default
  if @default_block
    self.value = @default_block.call
  else
    @default
  end
end