@@ -33,7 +33,32 @@ class RubyThreadLocalVar < AbstractThreadLocalVar
3333 LOCK = Mutex . new
3434 ARRAYS = { } # used as a hash set
3535 @@next = 0
36- private_constant :FREE , :LOCK , :ARRAYS
36+ QUEUE = Queue . new
37+ THREAD = Thread . new do
38+ while true
39+ method , i = QUEUE . pop
40+ case method
41+ when :thread_local_finalizer
42+ LOCK . synchronize do
43+ FREE . push ( i )
44+ # The cost of GC'ing a TLV is linear in the number of threads using TLVs
45+ # But that is natural! More threads means more storage is used per TLV
46+ # So naturally more CPU time is required to free more storage
47+ ARRAYS . each_value do |array |
48+ array [ i ] = nil
49+ end
50+ end
51+ when :thread_finalizer
52+ LOCK . synchronize do
53+ # The thread which used this thread-local array is now gone
54+ # So don't hold onto a reference to the array (thus blocking GC)
55+ ARRAYS . delete ( i )
56+ end
57+ end
58+ end
59+ end
60+
61+ private_constant :FREE , :LOCK , :ARRAYS , :QUEUE , :THREAD
3762
3863 # @!macro thread_local_var_method_get
3964 def value
@@ -77,37 +102,18 @@ def allocate_storage
77102 result
78103 end
79104 end
80- ObjectSpace . define_finalizer ( self , self . class . threadlocal_finalizer ( @index ) )
105+ ObjectSpace . define_finalizer ( self , self . class . thread_local_finalizer ( @index ) )
81106 end
82107
83108 # @!visibility private
84- def self . threadlocal_finalizer ( index )
85- proc do
86- Thread . new ( index ) do |index | # avoid error: can't be called from trap context
87- LOCK . synchronize do
88- FREE . push ( index )
89- # The cost of GC'ing a TLV is linear in the number of threads using TLVs
90- # But that is natural! More threads means more storage is used per TLV
91- # So naturally more CPU time is required to free more storage
92- ARRAYS . each_value do |array |
93- array [ index ] = nil
94- end
95- end
96- end
97- end
109+ def self . thread_local_finalizer ( index )
110+ proc { QUEUE . push [ :thread_local_finalizer , index ] }
98111 end
99112
100113 # @!visibility private
101114 def self . thread_finalizer ( id )
102- proc do
103- Thread . new ( id ) do |id | # avoid error: can't be called from trap context
104- LOCK . synchronize do
105- # The thread which used this thread-local array is now gone
106- # So don't hold onto a reference to the array (thus blocking GC)
107- ARRAYS . delete ( id )
108- end
109- end
110- end
115+ # avoid error: can't be called from trap context
116+ proc { QUEUE . push [ :thread_finalizer , id ] }
111117 end
112118
113119 private
0 commit comments