class Concurrent::RubyThreadLocalVar
@!visibility private @!macro internal_implementation_note
Constants
- ARRAYS
- FREE
@!visibility private
- LOCK
Protected Class Methods
thread_finalizer(array)
click to toggle source
@!visibility private
# File lib/concurrent/atomic/ruby_thread_local_var.rb, line 101 def self.thread_finalizer(array) proc do Thread.new do # avoid error: can't be called from trap context 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 end
threadlocal_finalizer(index)
click to toggle source
@!visibility private
# File lib/concurrent/atomic/ruby_thread_local_var.rb, line 84 def self.threadlocal_finalizer(index) proc do Thread.new do # avoid error: can't be called from trap context 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 end
Public Instance Methods
value()
click to toggle source
@!macro thread_local_var_method_get
# File lib/concurrent/atomic/ruby_thread_local_var.rb, line 39 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 55 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 72 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
default_for(thread)
click to toggle source
# File lib/concurrent/atomic/ruby_thread_local_var.rb, line 153 def default_for(thread) if @default_block raise "Cannot use default_for with default block" else @default end end
get_threadlocal_array(thread = Thread.current)
click to toggle source
# File lib/concurrent/atomic/ruby_thread_local_var.rb, line 117 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 121 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 138 def value_for(thread) if array = get_threadlocal_array(thread) value = array[@index] if value.nil? default_for(thread) elsif value.equal?(NULL) nil else value end else default_for(thread) end end