Module: Tins::ThreadLocal

Included in:
Object, Deflect, HashBFS, HashSymbolizeKeysRecursive
Defined in:
lib/tins/thread_local.rb

Overview

Provides thread-local storage capabilities for classes and modules. Thread-local variables are scoped to individual threads, allowing each thread to maintain its own copy of the variable value.

Examples:

Basic usage with a class

class MyClass
  extend Tins::ThreadLocal

  thread_local :counter, 0
  thread_local :name, "default"
end

# Each thread gets its own copy of the variables
t1 = Thread.new { puts MyClass.new.counter }  # => 0
t2 = Thread.new { puts MyClass.new.counter }  # => 0
t1.join; t2.join

Usage with default blocks

class Config
  extend Tins::ThreadLocal

  thread_local :database_url do
    ENV['DATABASE_URL'] || 'sqlite3://default.db'
  end
end

Instance-level thread local variables

class MyClass
  include Tins::ThreadLocal

  instance_thread_local :user_id, 0
end

Constant Summary collapse

@@cleanup =

Cleanup lambda that removes thread-local data when objects are garbage collected

lambda do |my_object_id|
  my_id = "__thread_local_#{my_object_id}__"
  for t in Thread.list
    t[my_id] = nil if t[my_id]
  end
end

Instance Method Summary collapse

Instance Method Details

#instance_thread_local(name, default_value = nil) {|void| ... } ⇒ self

Define a thread local variable for the current instance with name name. If the value value is given, it is used to initialize the variable.

Examples:

Basic usage

class MyClass
  include Tins::ThreadLocal

  instance_thread_local :user_id, 0
end

Parameters:

  • name (Symbol, String)

    The name of the thread-local variable

  • default_value (Object) (defaults to: nil)

    Optional default value for the variable

Yields:

  • (void)

    Optional block that returns the default value

Returns:

  • (self)


106
107
108
109
110
111
112
113
# File 'lib/tins/thread_local.rb', line 106

def instance_thread_local(name, default_value = nil, &default)
  class << self
    extend Tins::ThreadLocal
    self
  end.thread_local name, default_value, &default

  self
end

#thread_local(name, default_value = nil) {|void| ... } ⇒ self

Define a thread local variable named name in this module/class. If the value value is given, it is used to initialize the variable.

Examples:

With static default value

thread_local :counter, 0

With dynamic default value via block

thread_local :timestamp do
  Time.now
end

Parameters:

  • name (Symbol, String)

    The name of the thread-local variable

  • default_value (Object) (defaults to: nil)

    Optional default value for the variable

Yields:

  • (void)

    Optional block that returns the default value

Returns:

  • (self)

Raises:

  • (TypeError)

    If receiver is not a Module

  • (ArgumentError)

    If both default_value and default block are provided



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/tins/thread_local.rb', line 61

def thread_local(name, default_value = nil, &default)
  is_a?(Module) or raise TypeError, "receiver has to be a Module"

  default_value && default and raise ArgumentError,
    "require either default_value or default block"

  if default_value
    default = -> * { default_value }
  end

  name = name.to_s
  my_id = "__thread_local_#{__id__}__"

  ObjectSpace.define_finalizer(self, @@cleanup)

  define_method(name) do
    values = Thread.current[my_id] ||= {}
    if default && !values.key?(name)
      values[name] = default.call
    end
    values[name]
  end

  define_method("#{name}=") do |value|
    Thread.current[my_id] ||= {}
    Thread.current[my_id][name] = value
  end

  self
end