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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +51 -0
- data/Gemfile +11 -8
- data/{LICENSE.md → LICENSE.txt} +18 -20
- data/README.md +42 -7
- data/Rakefile +50 -48
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +9 -8
- data/lib/{concurrent-ruby.rb → concurrent-ruby/concurrent-ruby.rb} +0 -0
- data/lib/{concurrent.rb → concurrent-ruby/concurrent.rb} +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/agent.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/array.rb +9 -9
- data/lib/{concurrent → concurrent-ruby/concurrent}/async.rb +23 -20
- data/lib/{concurrent → concurrent-ruby/concurrent}/atom.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/abstract_thread_local_var.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_boolean.rb +2 -2
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_fixnum.rb +2 -2
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_markable_reference.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_reference.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/count_down_latch.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/cyclic_barrier.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/event.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/java_count_down_latch.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/java_thread_local_var.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_atomic_boolean.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_atomic_fixnum.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_count_down_latch.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/mutex_semaphore.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/read_write_lock.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/reentrant_read_write_lock.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/ruby_thread_local_var.rb +57 -40
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/semaphore.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/thread_local_var.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic_reference/mutex_atomic.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic_reference/numeric_cas_wrapper.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomics.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/copy_on_notify_observer_set.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/copy_on_write_observer_set.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/java_non_concurrent_priority_queue.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/lock_free_stack.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/atomic_reference_map_backend.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/mri_map_backend.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/non_concurrent_map_backend.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/synchronized_map_backend.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/non_concurrent_priority_queue.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/collection/ruby_non_concurrent_priority_queue.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/concern/deprecation.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/concern/dereferenceable.rb +2 -2
- data/lib/{concurrent → concurrent-ruby/concurrent}/concern/logging.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/concern/obligation.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/concern/observable.rb +0 -0
- data/lib/concurrent-ruby/concurrent/concurrent_ruby.jar +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/configuration.rb +13 -9
- data/lib/{concurrent → concurrent-ruby/concurrent}/constants.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/dataflow.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/delay.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/errors.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/exchanger.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/abstract_executor_service.rb +17 -23
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/cached_thread_pool.rb +4 -4
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/executor_service.rb +2 -2
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/fixed_thread_pool.rb +16 -12
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/immediate_executor.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/indirect_immediate_executor.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_executor_service.rb +19 -16
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_single_thread_executor.rb +4 -3
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/java_thread_pool_executor.rb +15 -2
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_executor_service.rb +0 -2
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_single_thread_executor.rb +0 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_thread_pool_executor.rb +20 -5
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/safe_task_executor.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serial_executor_service.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serialized_execution.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/serialized_execution_delegator.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/simple_executor_service.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/single_thread_executor.rb +1 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/thread_pool_executor.rb +2 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/timer_set.rb +13 -16
- data/lib/{concurrent → concurrent-ruby/concurrent}/executors.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/future.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/hash.rb +4 -4
- data/lib/{concurrent → concurrent-ruby/concurrent}/immutable_struct.rb +9 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/ivar.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/map.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/maybe.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/mutable_struct.rb +12 -2
- data/lib/{concurrent → concurrent-ruby/concurrent}/mvar.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/options.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/promise.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/promises.rb +348 -117
- data/lib/{concurrent → concurrent-ruby/concurrent}/re_include.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/scheduled_task.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/set.rb +5 -5
- data/lib/{concurrent → concurrent-ruby/concurrent}/settable_struct.rb +11 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_lockable_object.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_object.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/abstract_struct.rb +13 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/condition.rb +2 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/jruby_lockable_object.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/jruby_object.rb +1 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/lock.rb +2 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/lockable_object.rb +2 -2
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/mri_object.rb +1 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/mutex_lockable_object.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/object.rb +46 -20
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/rbx_lockable_object.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/rbx_object.rb +1 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/truffleruby_object.rb +1 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/volatile.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/synchronized_delegator.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/adder.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/cheap_lockable.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/data_structures.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/power_of_two_tuple.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/striped64.rb +1 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/volatile.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/thread_safe/util/xor_shift_random.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/timer_task.rb +0 -1
- data/lib/{concurrent → concurrent-ruby/concurrent}/tuple.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/tvar.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/utility/engine.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/utility/monotonic_time.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/utility/native_extension_loader.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/utility/native_integer.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/utility/processor_counter.rb +5 -0
- data/lib/concurrent-ruby/concurrent/version.rb +3 -0
- metadata +129 -129
- data/lib/concurrent/concurrent_ruby.jar +0 -0
- data/lib/concurrent/utility/at_exit.rb +0 -97
- data/lib/concurrent/version.rb +0 -4
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -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
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
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
|
|
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
|
-
#
|
|
25
|
-
#
|
|
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
|
|
File without changes
|
|
@@ -41,13 +41,13 @@ module Concurrent
|
|
|
41
41
|
#
|
|
42
42
|
# Explicitly sets the value to true.
|
|
43
43
|
#
|
|
44
|
-
# @return [Boolean] true
|
|
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
|
|
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)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -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
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
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 =
|
|
74
|
-
|
|
75
|
-
|
|
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.
|
|
94
|
+
def self.thread_local_finalizer(index)
|
|
85
95
|
proc do
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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(
|
|
108
|
+
def self.thread_finalizer(id)
|
|
102
109
|
proc do
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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
|
-
|
|
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
|
-
|
|
165
|
+
get_default
|
|
150
166
|
end
|
|
151
167
|
end
|
|
152
168
|
|
|
153
|
-
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
data/lib/{concurrent → concurrent-ruby/concurrent}/collection/copy_on_notify_observer_set.rb
RENAMED
|
File without changes
|
|
File without changes
|
data/lib/{concurrent → concurrent-ruby/concurrent}/collection/java_non_concurrent_priority_queue.rb
RENAMED
|
File without changes
|
data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/atomic_reference_map_backend.rb
RENAMED
|
File without changes
|
|
@@ -19,7 +19,7 @@ module Concurrent
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def compute_if_absent(key)
|
|
22
|
-
if stored_value =
|
|
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 }
|
data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/non_concurrent_map_backend.rb
RENAMED
|
File without changes
|
data/lib/{concurrent → concurrent-ruby/concurrent}/collection/map/synchronized_map_backend.rb
RENAMED
|
File without changes
|
data/lib/{concurrent → concurrent-ruby/concurrent}/collection/ruby_non_concurrent_priority_queue.rb
RENAMED
|
File without changes
|
|
File without changes
|
|
@@ -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
|
-
#
|
|
41
|
-
#
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
Binary file
|
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|