concurrent-ruby 1.1.3 → 1.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +51 -0
  3. data/Gemfile +11 -8
  4. data/{LICENSE.md → LICENSE.txt} +18 -20
  5. data/README.md +42 -7
  6. data/Rakefile +50 -48
  7. data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +9 -8
  8. data/lib/{concurrent-ruby.rb → concurrent-ruby/concurrent-ruby.rb} +0 -0
  9. data/lib/{concurrent.rb → concurrent-ruby/concurrent.rb} +0 -0
  10. data/lib/{concurrent → concurrent-ruby/concurrent}/agent.rb +0 -0
  11. data/lib/{concurrent → concurrent-ruby/concurrent}/array.rb +9 -9
  12. data/lib/{concurrent → concurrent-ruby/concurrent}/async.rb +23 -20
  13. data/lib/{concurrent → concurrent-ruby/concurrent}/atom.rb +1 -1
  14. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/abstract_thread_local_var.rb +0 -0
  15. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_boolean.rb +2 -2
  16. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_fixnum.rb +2 -2
  17. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_markable_reference.rb +0 -0
  18. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_reference.rb +0 -0
  19. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/count_down_latch.rb +1 -1
  20. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/cyclic_barrier.rb +0 -0
  21. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/event.rb +0 -0
  22. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/java_count_down_latch.rb +0 -0
  23. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/java_thread_local_var.rb +0 -0
  24. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_atomic_boolean.rb +0 -0
  25. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_atomic_fixnum.rb +0 -0
  26. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_count_down_latch.rb +0 -0
  27. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_semaphore.rb +0 -0
  28. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/read_write_lock.rb +0 -0
  29. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/reentrant_read_write_lock.rb +0 -0
  30. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/ruby_thread_local_var.rb +57 -40
  31. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/semaphore.rb +0 -0
  32. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/thread_local_var.rb +1 -1
  33. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic_reference/mutex_atomic.rb +0 -0
  34. data/lib/{concurrent → concurrent-ruby/concurrent}/atomic_reference/numeric_cas_wrapper.rb +0 -0
  35. data/lib/{concurrent → concurrent-ruby/concurrent}/atomics.rb +0 -0
  36. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/copy_on_notify_observer_set.rb +0 -0
  37. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/copy_on_write_observer_set.rb +0 -0
  38. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/java_non_concurrent_priority_queue.rb +0 -0
  39. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/lock_free_stack.rb +1 -1
  40. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/atomic_reference_map_backend.rb +0 -0
  41. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/mri_map_backend.rb +1 -1
  42. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/non_concurrent_map_backend.rb +0 -0
  43. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/synchronized_map_backend.rb +0 -0
  44. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/non_concurrent_priority_queue.rb +1 -1
  45. data/lib/{concurrent → concurrent-ruby/concurrent}/collection/ruby_non_concurrent_priority_queue.rb +0 -0
  46. data/lib/{concurrent → concurrent-ruby/concurrent}/concern/deprecation.rb +0 -0
  47. data/lib/{concurrent → concurrent-ruby/concurrent}/concern/dereferenceable.rb +2 -2
  48. data/lib/{concurrent → concurrent-ruby/concurrent}/concern/logging.rb +0 -0
  49. data/lib/{concurrent → concurrent-ruby/concurrent}/concern/obligation.rb +0 -0
  50. data/lib/{concurrent → concurrent-ruby/concurrent}/concern/observable.rb +0 -0
  51. data/lib/concurrent-ruby/concurrent/concurrent_ruby.jar +0 -0
  52. data/lib/{concurrent → concurrent-ruby/concurrent}/configuration.rb +13 -9
  53. data/lib/{concurrent → concurrent-ruby/concurrent}/constants.rb +0 -0
  54. data/lib/{concurrent → concurrent-ruby/concurrent}/dataflow.rb +0 -0
  55. data/lib/{concurrent → concurrent-ruby/concurrent}/delay.rb +0 -0
  56. data/lib/{concurrent → concurrent-ruby/concurrent}/errors.rb +0 -0
  57. data/lib/{concurrent → concurrent-ruby/concurrent}/exchanger.rb +0 -0
  58. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/abstract_executor_service.rb +17 -23
  59. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/cached_thread_pool.rb +4 -4
  60. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/executor_service.rb +2 -2
  61. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/fixed_thread_pool.rb +16 -12
  62. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/immediate_executor.rb +0 -0
  63. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/indirect_immediate_executor.rb +0 -0
  64. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_executor_service.rb +19 -16
  65. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_single_thread_executor.rb +4 -3
  66. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_thread_pool_executor.rb +15 -2
  67. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_executor_service.rb +0 -2
  68. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_single_thread_executor.rb +0 -1
  69. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_thread_pool_executor.rb +20 -5
  70. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/safe_task_executor.rb +0 -0
  71. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serial_executor_service.rb +0 -0
  72. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serialized_execution.rb +0 -0
  73. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serialized_execution_delegator.rb +0 -0
  74. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/simple_executor_service.rb +1 -1
  75. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/single_thread_executor.rb +1 -0
  76. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/thread_pool_executor.rb +2 -1
  77. data/lib/{concurrent → concurrent-ruby/concurrent}/executor/timer_set.rb +13 -16
  78. data/lib/{concurrent → concurrent-ruby/concurrent}/executors.rb +0 -0
  79. data/lib/{concurrent → concurrent-ruby/concurrent}/future.rb +0 -0
  80. data/lib/{concurrent → concurrent-ruby/concurrent}/hash.rb +4 -4
  81. data/lib/{concurrent → concurrent-ruby/concurrent}/immutable_struct.rb +9 -1
  82. data/lib/{concurrent → concurrent-ruby/concurrent}/ivar.rb +0 -0
  83. data/lib/{concurrent → concurrent-ruby/concurrent}/map.rb +1 -1
  84. data/lib/{concurrent → concurrent-ruby/concurrent}/maybe.rb +0 -0
  85. data/lib/{concurrent → concurrent-ruby/concurrent}/mutable_struct.rb +12 -2
  86. data/lib/{concurrent → concurrent-ruby/concurrent}/mvar.rb +0 -0
  87. data/lib/{concurrent → concurrent-ruby/concurrent}/options.rb +0 -0
  88. data/lib/{concurrent → concurrent-ruby/concurrent}/promise.rb +0 -0
  89. data/lib/{concurrent → concurrent-ruby/concurrent}/promises.rb +348 -117
  90. data/lib/{concurrent → concurrent-ruby/concurrent}/re_include.rb +0 -0
  91. data/lib/{concurrent → concurrent-ruby/concurrent}/scheduled_task.rb +0 -0
  92. data/lib/{concurrent → concurrent-ruby/concurrent}/set.rb +5 -5
  93. data/lib/{concurrent → concurrent-ruby/concurrent}/settable_struct.rb +11 -1
  94. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization.rb +0 -0
  95. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_lockable_object.rb +0 -0
  96. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_object.rb +0 -0
  97. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_struct.rb +13 -1
  98. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/condition.rb +2 -0
  99. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/jruby_lockable_object.rb +0 -0
  100. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/jruby_object.rb +1 -0
  101. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/lock.rb +2 -0
  102. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/lockable_object.rb +2 -2
  103. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/mri_object.rb +1 -0
  104. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/mutex_lockable_object.rb +0 -0
  105. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/object.rb +46 -20
  106. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/rbx_lockable_object.rb +0 -0
  107. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/rbx_object.rb +1 -0
  108. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/truffleruby_object.rb +1 -0
  109. data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/volatile.rb +0 -0
  110. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/synchronized_delegator.rb +0 -0
  111. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util.rb +0 -0
  112. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/adder.rb +0 -0
  113. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/cheap_lockable.rb +0 -0
  114. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/data_structures.rb +0 -0
  115. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/power_of_two_tuple.rb +0 -0
  116. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/striped64.rb +1 -1
  117. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/volatile.rb +0 -0
  118. data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/xor_shift_random.rb +0 -0
  119. data/lib/{concurrent → concurrent-ruby/concurrent}/timer_task.rb +0 -1
  120. data/lib/{concurrent → concurrent-ruby/concurrent}/tuple.rb +0 -0
  121. data/lib/{concurrent → concurrent-ruby/concurrent}/tvar.rb +0 -0
  122. data/lib/{concurrent → concurrent-ruby/concurrent}/utility/engine.rb +0 -0
  123. data/lib/{concurrent → concurrent-ruby/concurrent}/utility/monotonic_time.rb +0 -0
  124. data/lib/{concurrent → concurrent-ruby/concurrent}/utility/native_extension_loader.rb +0 -0
  125. data/lib/{concurrent → concurrent-ruby/concurrent}/utility/native_integer.rb +0 -0
  126. data/lib/{concurrent → concurrent-ruby/concurrent}/utility/processor_counter.rb +5 -0
  127. data/lib/concurrent-ruby/concurrent/version.rb +3 -0
  128. metadata +129 -129
  129. data/lib/concurrent/concurrent_ruby.jar +0 -0
  130. data/lib/concurrent/utility/at_exit.rb +0 -97
  131. data/lib/concurrent/version.rb +0 -4
@@ -10,19 +10,20 @@ module Concurrent
10
10
  # or writing at a time. This includes iteration methods like `#each`.
11
11
  #
12
12
  # @note `a += b` is **not** a **thread-safe** operation on
13
- # `Concurrent::Array`. It reads array `a`, then it creates new `Concurrent::Array`
14
- # which is concatenation of `a` and `b`, then it writes the concatenation to `a`.
15
- # The read and write are independent operations they do not form a single atomic
16
- # operation therefore when two `+=` operations are executed concurrently updates
17
- # may be lost. Use `#concat` instead.
13
+ # `Concurrent::Array`. It reads array `a`, then it creates new `Concurrent::Array`
14
+ # which is concatenation of `a` and `b`, then it writes the concatenation to `a`.
15
+ # The read and write are independent operations they do not form a single atomic
16
+ # operation therefore when two `+=` operations are executed concurrently updates
17
+ # may be lost. Use `#concat` instead.
18
18
  #
19
- # @see http://ruby-doc.org/core-2.2.0/Array.html Ruby standard library `Array`
19
+ # @see http://ruby-doc.org/core/Array.html Ruby standard library `Array`
20
20
 
21
21
  # @!macro internal_implementation_note
22
22
  ArrayImplementation = case
23
23
  when Concurrent.on_cruby?
24
- # Because MRI never runs code in parallel, the existing
25
- # non-thread-safe structures should usually work fine.
24
+ # Array is thread-safe in practice because CRuby runs
25
+ # threads one at a time and does not do context
26
+ # switching during the execution of C functions.
26
27
  ::Array
27
28
 
28
29
  when Concurrent.on_jruby?
@@ -63,4 +64,3 @@ module Concurrent
63
64
  end
64
65
 
65
66
  end
66
-
@@ -58,26 +58,6 @@ module Concurrent
58
58
  # end
59
59
  # ```
60
60
  #
61
- # When defining a constructor it is critical that the first line be a call to
62
- # `super` with no arguments. The `super` method initializes the background
63
- # thread and other asynchronous components.
64
- #
65
- # ```
66
- # class BackgroundLogger
67
- # include Concurrent::Async
68
- #
69
- # def initialize(level)
70
- # super()
71
- # @logger = Logger.new(STDOUT)
72
- # @logger.level = level
73
- # end
74
- #
75
- # def info(msg)
76
- # @logger.info(msg)
77
- # end
78
- # end
79
- # ```
80
- #
81
61
  # Mixing this module into a class provides each object two proxy methods:
82
62
  # `async` and `await`. These methods are thread safe with respect to the
83
63
  # enclosing object. The former proxy allows methods to be called
@@ -309,6 +289,7 @@ module Concurrent
309
289
  @delegate = delegate
310
290
  @queue = []
311
291
  @executor = Concurrent.global_io_executor
292
+ @ruby_pid = $$
312
293
  end
313
294
 
314
295
  # Delegates method calls to the wrapped object.
@@ -326,6 +307,7 @@ module Concurrent
326
307
 
327
308
  ivar = Concurrent::IVar.new
328
309
  synchronize do
310
+ reset_if_forked
329
311
  @queue.push [ivar, method, args, block]
330
312
  @executor.post { perform } if @queue.length == 1
331
313
  end
@@ -333,6 +315,13 @@ module Concurrent
333
315
  ivar
334
316
  end
335
317
 
318
+ # Check whether the method is responsive
319
+ #
320
+ # @param [Symbol] method the method being called
321
+ def respond_to_missing?(method, include_private = false)
322
+ @delegate.respond_to?(method) || super
323
+ end
324
+
336
325
  # Perform all enqueued tasks.
337
326
  #
338
327
  # This method must be called from within the executor. It must not be
@@ -354,6 +343,13 @@ module Concurrent
354
343
  end
355
344
  end
356
345
  end
346
+
347
+ def reset_if_forked
348
+ if $$ != @ruby_pid
349
+ @queue.clear
350
+ @ruby_pid = $$
351
+ end
352
+ end
357
353
  end
358
354
  private_constant :AsyncDelegator
359
355
 
@@ -383,6 +379,13 @@ module Concurrent
383
379
  ivar.wait
384
380
  ivar
385
381
  end
382
+
383
+ # Check whether the method is responsive
384
+ #
385
+ # @param [Symbol] method the method being called
386
+ def respond_to_missing?(method, include_private = false)
387
+ @delegate.respond_to?(method) || super
388
+ end
386
389
  end
387
390
  private_constant :AwaitDelegator
388
391
 
@@ -18,7 +18,7 @@ require 'concurrent/synchronization'
18
18
  # uncoordinated, *synchronous* change of individual values. Best used when
19
19
  # the value will undergo frequent reads but only occasional, though complex,
20
20
  # updates. Suitable when the result of an update must be known immediately.
21
- # * *{Concurrent::AtomicReference}:* A simple object reference that can be
21
+ # * *{Concurrent::AtomicReference}:* A simple object reference that can be updated
22
22
  # atomically. Updates are synchronous but fast. Best used when updates a
23
23
  # simple set operations. Not suitable when updates are complex.
24
24
  # {Concurrent::AtomicBoolean} and {Concurrent::AtomicFixnum} are similar
@@ -41,13 +41,13 @@ module Concurrent
41
41
  #
42
42
  # Explicitly sets the value to true.
43
43
  #
44
- # @return [Boolean] true is value has changed, otherwise false
44
+ # @return [Boolean] true if value has changed, otherwise false
45
45
 
46
46
  # @!macro atomic_boolean_method_make_false
47
47
  #
48
48
  # Explicitly sets the value to false.
49
49
  #
50
- # @return [Boolean] true is value has changed, otherwise false
50
+ # @return [Boolean] true if value has changed, otherwise false
51
51
 
52
52
  ###################################################################
53
53
 
@@ -79,10 +79,10 @@ module Concurrent
79
79
  # @!method value=(value)
80
80
  # @!macro atomic_fixnum_method_value_set
81
81
  #
82
- # @!method increment(delta)
82
+ # @!method increment(delta = 1)
83
83
  # @!macro atomic_fixnum_method_increment
84
84
  #
85
- # @!method decrement(delta)
85
+ # @!method decrement(delta = 1)
86
86
  # @!macro atomic_fixnum_method_decrement
87
87
  #
88
88
  # @!method compare_and_set(expect, update)
@@ -1,6 +1,6 @@
1
+ require 'concurrent/utility/engine'
1
2
  require 'concurrent/atomic/mutex_count_down_latch'
2
3
  require 'concurrent/atomic/java_count_down_latch'
3
- require 'concurrent/utility/engine'
4
4
 
5
5
  module Concurrent
6
6
 
@@ -28,16 +28,31 @@ module Concurrent
28
28
  # But when a Thread is GC'd, we need to drop the reference to its thread-local
29
29
  # array, so we don't leak memory
30
30
 
31
- # @!visibility private
32
- FREE = []
33
- LOCK = Mutex.new
34
- ARRAYS = {} # used as a hash set
35
- @@next = 0
36
- private_constant :FREE, :LOCK, :ARRAYS
31
+ FREE = []
32
+ LOCK = Mutex.new
33
+ THREAD_LOCAL_ARRAYS = {} # used as a hash set
34
+
35
+ # synchronize when not on MRI
36
+ # on MRI using lock in finalizer leads to "can't be called from trap context" error
37
+ # so the code is carefully written to be tread-safe on MRI relying on GIL
38
+
39
+ if Concurrent.on_cruby?
40
+ # @!visibility private
41
+ def self.semi_sync(&block)
42
+ block.call
43
+ end
44
+ else
45
+ # @!visibility private
46
+ def self.semi_sync(&block)
47
+ LOCK.synchronize(&block)
48
+ end
49
+ end
50
+
51
+ private_constant :FREE, :LOCK, :THREAD_LOCAL_ARRAYS
37
52
 
38
53
  # @!macro thread_local_var_method_get
39
54
  def value
40
- if array = get_threadlocal_array
55
+ if (array = get_threadlocal_array)
41
56
  value = array[@index]
42
57
  if value.nil?
43
58
  default
@@ -57,10 +72,10 @@ module Concurrent
57
72
  # We could keep the thread-local arrays in a hash, keyed by Thread
58
73
  # But why? That would require locking
59
74
  # Using Ruby's built-in thread-local storage is faster
60
- unless array = get_threadlocal_array(me)
75
+ unless (array = get_threadlocal_array(me))
61
76
  array = set_threadlocal_array([], me)
62
- LOCK.synchronize { ARRAYS[array.object_id] = array }
63
- ObjectSpace.define_finalizer(me, self.class.thread_finalizer(array))
77
+ self.class.semi_sync { THREAD_LOCAL_ARRAYS[array.object_id] = array }
78
+ ObjectSpace.define_finalizer(me, self.class.thread_finalizer(array.object_id))
64
79
  end
65
80
  array[@index] = (value.nil? ? NULL : value)
66
81
  value
@@ -70,48 +85,49 @@ module Concurrent
70
85
 
71
86
  # @!visibility private
72
87
  def allocate_storage
73
- @index = LOCK.synchronize do
74
- FREE.pop || begin
75
- result = @@next
76
- @@next += 1
77
- result
78
- end
79
- end
80
- ObjectSpace.define_finalizer(self, self.class.threadlocal_finalizer(@index))
88
+ @index = FREE.pop || next_index
89
+
90
+ ObjectSpace.define_finalizer(self, self.class.thread_local_finalizer(@index))
81
91
  end
82
92
 
83
93
  # @!visibility private
84
- def self.threadlocal_finalizer(index)
94
+ def self.thread_local_finalizer(index)
85
95
  proc do
86
- Thread.new do # 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
+ semi_sync do
97
+ # The cost of GC'ing a TLV is linear in the number of threads using TLVs
98
+ # But that is natural! More threads means more storage is used per TLV
99
+ # So naturally more CPU time is required to free more storage
100
+ THREAD_LOCAL_ARRAYS.each_value { |array| array[index] = nil }
101
+ # free index has to be published after the arrays are cleared
102
+ FREE.push(index)
96
103
  end
97
104
  end
98
105
  end
99
106
 
100
107
  # @!visibility private
101
- def self.thread_finalizer(array)
108
+ def self.thread_finalizer(id)
102
109
  proc do
103
- Thread.new do # 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(array.object_id)
108
- end
110
+ semi_sync do
111
+ # The thread which used this thread-local array is now gone
112
+ # So don't hold onto a reference to the array (thus blocking GC)
113
+ THREAD_LOCAL_ARRAYS.delete(id)
109
114
  end
110
115
  end
111
116
  end
112
117
 
113
118
  private
114
119
 
120
+ # noinspection RubyClassVariableUsageInspection
121
+ @@next = 0
122
+ # noinspection RubyClassVariableUsageInspection
123
+ def next_index
124
+ LOCK.synchronize do
125
+ result = @@next
126
+ @@next += 1
127
+ result
128
+ end
129
+ end
130
+
115
131
  if Thread.instance_methods.include?(:thread_variable_get)
116
132
 
117
133
  def get_threadlocal_array(thread = Thread.current)
@@ -136,21 +152,22 @@ module Concurrent
136
152
  # This exists only for use in testing
137
153
  # @!visibility private
138
154
  def value_for(thread)
139
- if array = get_threadlocal_array(thread)
155
+ if (array = get_threadlocal_array(thread))
140
156
  value = array[@index]
141
157
  if value.nil?
142
- default_for(thread)
158
+ get_default
143
159
  elsif value.equal?(NULL)
144
160
  nil
145
161
  else
146
162
  value
147
163
  end
148
164
  else
149
- default_for(thread)
165
+ get_default
150
166
  end
151
167
  end
152
168
 
153
- def default_for(thread)
169
+ # @!visibility private
170
+ def get_default
154
171
  if @default_block
155
172
  raise "Cannot use default_for with default block"
156
173
  else
@@ -1,6 +1,6 @@
1
+ require 'concurrent/utility/engine'
1
2
  require 'concurrent/atomic/ruby_thread_local_var'
2
3
  require 'concurrent/atomic/java_thread_local_var'
3
- require 'concurrent/utility/engine'
4
4
 
5
5
  module Concurrent
6
6
 
@@ -53,7 +53,7 @@ module Concurrent
53
53
 
54
54
  # @param [Node] head
55
55
  # @return [true, false]
56
- def empty?(head = self.head)
56
+ def empty?(head = head())
57
57
  head.equal? EMPTY
58
58
  end
59
59
 
@@ -19,7 +19,7 @@ module Concurrent
19
19
  end
20
20
 
21
21
  def compute_if_absent(key)
22
- if stored_value = _get(key) # fast non-blocking path for the most likely case
22
+ if NULL != (stored_value = @backend.fetch(key, NULL)) # fast non-blocking path for the most likely case
23
23
  stored_value
24
24
  else
25
25
  @write_lock.synchronize { super }
@@ -1,6 +1,6 @@
1
+ require 'concurrent/utility/engine'
1
2
  require 'concurrent/collection/java_non_concurrent_priority_queue'
2
3
  require 'concurrent/collection/ruby_non_concurrent_priority_queue'
3
- require 'concurrent/utility/engine'
4
4
 
5
5
  module Concurrent
6
6
  module Collection
@@ -37,8 +37,8 @@ module Concurrent
37
37
  # returning data to the caller (dereferencing).
38
38
  #
39
39
  # @note Most classes that include this module will call `#set_deref_options`
40
- # from within the constructor, thus allowing these options to be set at
41
- # object creation.
40
+ # from within the constructor, thus allowing these options to be set at
41
+ # object creation.
42
42
  #
43
43
  # @param [Hash] opts the options defining dereference behavior.
44
44
  # @option opts [String] :dup_on_deref (false) call `#dup` before returning the data
@@ -3,13 +3,14 @@ require 'concurrent/delay'
3
3
  require 'concurrent/errors'
4
4
  require 'concurrent/atomic/atomic_reference'
5
5
  require 'concurrent/concern/logging'
6
+ require 'concurrent/concern/deprecation'
6
7
  require 'concurrent/executor/immediate_executor'
7
8
  require 'concurrent/executor/cached_thread_pool'
8
- require 'concurrent/utility/at_exit'
9
9
  require 'concurrent/utility/processor_counter'
10
10
 
11
11
  module Concurrent
12
12
  extend Concern::Logging
13
+ extend Concern::Deprecation
13
14
 
14
15
  autoload :Options, 'concurrent/options'
15
16
  autoload :TimerSet, 'concurrent/executor/timer_set'
@@ -97,15 +98,15 @@ module Concurrent
97
98
  end
98
99
 
99
100
  # @!visibility private
100
- GLOBAL_FAST_EXECUTOR = Delay.new { Concurrent.new_fast_executor(auto_terminate: true) }
101
+ GLOBAL_FAST_EXECUTOR = Delay.new { Concurrent.new_fast_executor }
101
102
  private_constant :GLOBAL_FAST_EXECUTOR
102
103
 
103
104
  # @!visibility private
104
- GLOBAL_IO_EXECUTOR = Delay.new { Concurrent.new_io_executor(auto_terminate: true) }
105
+ GLOBAL_IO_EXECUTOR = Delay.new { Concurrent.new_io_executor }
105
106
  private_constant :GLOBAL_IO_EXECUTOR
106
107
 
107
108
  # @!visibility private
108
- GLOBAL_TIMER_SET = Delay.new { TimerSet.new(auto_terminate: true) }
109
+ GLOBAL_TIMER_SET = Delay.new { TimerSet.new }
109
110
  private_constant :GLOBAL_TIMER_SET
110
111
 
111
112
  # @!visibility private
@@ -115,7 +116,7 @@ module Concurrent
115
116
  # Disables AtExit handlers including pool auto-termination handlers.
116
117
  # When disabled it will be the application programmer's responsibility
117
118
  # to ensure that the handlers are shutdown properly prior to application
118
- # exit by calling {AtExit.run} method.
119
+ # exit by calling `AtExit.run` method.
119
120
  #
120
121
  # @note this option should be needed only because of `at_exit` ordering
121
122
  # issues which may arise when running some of the testing frameworks.
@@ -125,9 +126,10 @@ module Concurrent
125
126
  # @note This method should *never* be called
126
127
  # from within a gem. It should *only* be used from within the main
127
128
  # application and even then it should be used only when necessary.
128
- # @see AtExit
129
+ # @deprecated Has no effect since it is no longer needed, see https://github.com/ruby-concurrency/concurrent-ruby/pull/841.
130
+ #
129
131
  def self.disable_at_exit_handlers!
130
- AtExit.enabled = false
132
+ deprecated "Method #disable_at_exit_handlers! has no effect since it is no longer needed, see https://github.com/ruby-concurrency/concurrent-ruby/pull/841."
131
133
  end
132
134
 
133
135
  # Global thread pool optimized for short, fast *operations*.
@@ -171,14 +173,16 @@ module Concurrent
171
173
  auto_terminate: opts.fetch(:auto_terminate, true),
172
174
  idletime: 60, # 1 minute
173
175
  max_queue: 0, # unlimited
174
- fallback_policy: :abort # shouldn't matter -- 0 max queue
176
+ fallback_policy: :abort, # shouldn't matter -- 0 max queue
177
+ name: "fast"
175
178
  )
176
179
  end
177
180
 
178
181
  def self.new_io_executor(opts = {})
179
182
  CachedThreadPool.new(
180
183
  auto_terminate: opts.fetch(:auto_terminate, true),
181
- fallback_policy: :abort # shouldn't matter -- 0 max queue
184
+ fallback_policy: :abort, # shouldn't matter -- 0 max queue
185
+ name: "io"
182
186
  )
183
187
  end
184
188
  end