class Concurrent::RubyThreadLocalVar
@!visibility private @!macro internal_implementation_note
Constants
- ARRAYS
- FREE
@!visibility private
- LOCK
Public Class Methods
new(default = nil)
click to toggle source
@!macro [attach] thread_local_var_method_initialize
Creates a thread local variable. @param [Object] default the default value when otherwise unset
# File lib/concurrent/atomic/ruby_thread_local_var.rb, line 43 def initialize(default = nil) @default = default allocate_storage end
Protected Class Methods
thread_finalizer(array)
click to toggle source
@!visibility private
# File lib/concurrent/atomic/ruby_thread_local_var.rb, line 122 def self.thread_finalizer(array) proc do LOCK.synchronize do # The thread which used this thread-local array is now gone # So don't hold onto a reference to the array (thus blocking GC) ARRAYS.delete(array.object_id) end end end
threadlocal_finalizer(index)
click to toggle source
@!visibility private
# File lib/concurrent/atomic/ruby_thread_local_var.rb, line 107 def self.threadlocal_finalizer(index) proc do LOCK.synchronize do FREE.push(index) # The cost of GC'ing a TLV is linear in the number of threads using TLVs # But that is natural! More threads means more storage is used per TLV # So naturally more CPU time is required to free more storage ARRAYS.each_value do |array| array[index] = nil end end end end
Public Instance Methods
bind(value) { || ... }
click to toggle source
@!macro thread_local_var_method_bind
# File lib/concurrent/atomic/ruby_thread_local_var.rb, line 80 def bind(value, &block) if block_given? old_value = self.value begin self.value = value yield ensure self.value = old_value end end end
value()
click to toggle source
@!macro thread_local_var_method_get
# File lib/concurrent/atomic/ruby_thread_local_var.rb, line 49 def value if array = get_threadlocal_array value = array[@index] if value.nil? @default elsif value.equal?(NULL) nil else value end else @default end end
value=(value)
click to toggle source
@!macro thread_local_var_method_set
# File lib/concurrent/atomic/ruby_thread_local_var.rb, line 65 def value=(value) me = Thread.current # We could keep the thread-local arrays in a hash, keyed by Thread # But why? That would require locking # Using Ruby's built-in thread-local storage is faster unless array = get_threadlocal_array(me) array = set_threadlocal_array([], me) LOCK.synchronize { ARRAYS[array.object_id] = array } ObjectSpace.define_finalizer(me, self.class.thread_finalizer(array)) end array[@index] = (value.nil? ? NULL : value) value end
Protected Instance Methods
allocate_storage()
click to toggle source
@!visibility private
# File lib/concurrent/atomic/ruby_thread_local_var.rb, line 95 def allocate_storage @index = LOCK.synchronize do FREE.pop || begin result = @@next @@next += 1 result end end ObjectSpace.define_finalizer(self, self.class.threadlocal_finalizer(@index)) end
Private Instance Methods
get_threadlocal_array(thread = Thread.current)
click to toggle source
# File lib/concurrent/atomic/ruby_thread_local_var.rb, line 136 def get_threadlocal_array(thread = Thread.current) thread.thread_variable_get(:__threadlocal_array__) end
set_threadlocal_array(array, thread = Thread.current)
click to toggle source
# File lib/concurrent/atomic/ruby_thread_local_var.rb, line 140 def set_threadlocal_array(array, thread = Thread.current) thread.thread_variable_set(:__threadlocal_array__, array) end
value_for(thread)
click to toggle source
This exists only for use in testing @!visibility private
# File lib/concurrent/atomic/ruby_thread_local_var.rb, line 157 def value_for(thread) if array = get_threadlocal_array(thread) value = array[@index] if value.nil? @default elsif value.equal?(NULL) nil else value end else @default end end