123456789_123456789_123456789_123456789_123456789_

Class: Concurrent::ThreadLocalVar

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

Overview

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

This is similar to Ruby’s built-in thread-local variables (Thread#thread_variable_get), but with these major advantages:

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

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

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

## Thread-safe Variable Classes

Each of the thread-safe variable classes is designed to solve a different problem. In general:

  • *Agent:* Shared, mutable variable providing independent, uncoordinated, asynchronous change of individual values. Best used when the value will undergo frequent, complex updates. Suitable when the result of an update does not need to be known immediately.

  • *Atom:* Shared, mutable variable providing independent, uncoordinated, synchronous change of individual values. Best used when the value will undergo frequent reads but only occasional, though complex, updates. Suitable when the result of an update must be known immediately.

  • *AtomicReference:* A simple object reference that can be updated atomically. Updates are synchronous but fast. Best used when updates a simple set operations. Not suitable when updates are complex. AtomicBoolean and AtomicFixnum are similar but optimized for the given data type.

  • *Exchanger:* Shared, stateless synchronization point. Used when two or more threads need to exchange data. The threads will pair then block on each other until the exchange is complete.

  • *MVar:* Shared synchronization point. Used when one thread must give a value to another, which must take the value. The threads will block on each other until the exchange is complete.

  • *ThreadLocalVar:* Shared, mutable, isolated variable which holds a different value for each thread which has access. Often used as an instance variable in objects which must maintain different state for different threads.

  • *TVar:* Shared, mutable variables which provide coordinated, synchronous, change of many stated. Used when multiple value must change together, in an all-or-nothing transaction.

Examples:

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

t1 = Thread.new do
  v.value #=> 14
  v.value = 1
  v.value #=> 1
end

t2 = Thread.new do
  v.value #=> 14
  v.value = 2
  v.value #=> 2
end

v.value #=> 14

Constant Summary

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Constructor Details

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

Creates a thread 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 thread

[ GitHub ]

  
# File 'lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb', line 51

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 thread’s copy of this thread-local variable.

Returns:

  • (Object)

    the current value

[ GitHub ]

  
# File 'lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb', line 70

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

#value=(value) ⇒ Object (rw)

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

Parameters:

  • value (Object)

    the value to set

Returns:

[ GitHub ]

  
# File 'lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb', line 78

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

Instance Method Details

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

Bind the given value to thread 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/thread_local_var.rb', line 88

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/thread_local_var.rb', line 103

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