Class: Concurrent::FiberLocalVar

Inherits:
Object
  • Object
show all
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[:name]), 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 collapse

LOCALS =
FiberLocals.new

Instance Method Summary collapse

Constructor Details

#initialize(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



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

  • (Object)

    the value



86
87
88
89
90
91
92
93
94
95
96
# 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

#valueObject

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

Returns:

  • (Object)

    the current value



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

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

#value=(value) ⇒ Object

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

Parameters:

  • value (Object)

    the value to set

Returns:

  • (Object)

    the new value



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

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