concurrent-ruby 1.1.5 → 1.1.10
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 +65 -1
- data/Gemfile +6 -10
- data/{LICENSE.md → LICENSE.txt} +18 -20
- data/README.md +46 -23
- data/Rakefile +46 -44
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java +0 -0
- data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java +52 -22
- data/lib/{concurrent → concurrent-ruby/concurrent}/agent.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/array.rb +6 -6
- data/lib/{concurrent → concurrent-ruby/concurrent}/async.rb +10 -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 +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_markable_reference.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/atomic_reference.rb +1 -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 +2 -2
- 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 +18 -2
- 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 +4 -6
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/ruby_thread_local_var.rb +60 -40
- data/lib/{concurrent → concurrent-ruby/concurrent}/atomic/semaphore.rb +26 -5
- 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 +0 -0
- 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-ruby/concurrent/collection/map/truffleruby_map_backend.rb +14 -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 +11 -1
- 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 +33 -36
- 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 +29 -15
- 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 -7
- 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 +19 -2
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/ruby_executor_service.rb +10 -6
- 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 +46 -42
- data/lib/{concurrent → concurrent-ruby/concurrent}/executor/safe_task_executor.rb +5 -5
- 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 +0 -1
- 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 +1 -1
- 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 +14 -5
- 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 +1 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/promises.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/re_include.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/scheduled_task.rb +29 -16
- data/lib/{concurrent → concurrent-ruby/concurrent}/set.rb +19 -11
- data/lib/{concurrent → concurrent-ruby/concurrent}/settable_struct.rb +11 -1
- 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 +11 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/condition.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/jruby_lockable_object.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/jruby_object.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/lock.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/lockable_object.rb +3 -5
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/mri_object.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/mutex_lockable_object.rb +12 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/object.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/rbx_lockable_object.rb +6 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/rbx_object.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/truffleruby_object.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization/volatile.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/synchronization.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/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 +26 -1
- 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}/thread_safe/util.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/timer_task.rb +11 -34
- data/lib/{concurrent → concurrent-ruby/concurrent}/tuple.rb +0 -0
- data/lib/{concurrent → concurrent-ruby/concurrent}/tvar.rb +19 -56
- data/lib/{concurrent → concurrent-ruby/concurrent}/utility/engine.rb +0 -0
- data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +90 -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 -33
- data/lib/concurrent-ruby/concurrent/version.rb +3 -0
- data/lib/concurrent-ruby/concurrent-ruby.rb +5 -0
- data/lib/{concurrent.rb → concurrent-ruby/concurrent.rb} +0 -0
- metadata +132 -132
- data/lib/concurrent/concurrent_ruby.jar +0 -0
- data/lib/concurrent/utility/at_exit.rb +0 -97
- data/lib/concurrent/utility/monotonic_time.rb +0 -58
- data/lib/concurrent/version.rb +0 -3
- data/lib/concurrent-ruby.rb +0 -1
@@ -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
|
@@ -292,6 +272,7 @@ module Concurrent
|
|
292
272
|
obj.send(:init_synchronization)
|
293
273
|
obj
|
294
274
|
end
|
275
|
+
ruby2_keywords :new if respond_to?(:ruby2_keywords, true)
|
295
276
|
end
|
296
277
|
private_constant :ClassMethods
|
297
278
|
|
@@ -309,6 +290,7 @@ module Concurrent
|
|
309
290
|
@delegate = delegate
|
310
291
|
@queue = []
|
311
292
|
@executor = Concurrent.global_io_executor
|
293
|
+
@ruby_pid = $$
|
312
294
|
end
|
313
295
|
|
314
296
|
# Delegates method calls to the wrapped object.
|
@@ -326,6 +308,7 @@ module Concurrent
|
|
326
308
|
|
327
309
|
ivar = Concurrent::IVar.new
|
328
310
|
synchronize do
|
311
|
+
reset_if_forked
|
329
312
|
@queue.push [ivar, method, args, block]
|
330
313
|
@executor.post { perform } if @queue.length == 1
|
331
314
|
end
|
@@ -361,6 +344,13 @@ module Concurrent
|
|
361
344
|
end
|
362
345
|
end
|
363
346
|
end
|
347
|
+
|
348
|
+
def reset_if_forked
|
349
|
+
if $$ != @ruby_pid
|
350
|
+
@queue.clear
|
351
|
+
@ruby_pid = $$
|
352
|
+
end
|
353
|
+
end
|
364
354
|
end
|
365
355
|
private_constant :AsyncDelegator
|
366
356
|
|
@@ -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
|
|
File without changes
|
File without changes
|
@@ -170,6 +170,7 @@ module Concurrent
|
|
170
170
|
alias_method :compare_and_swap, :compare_and_set
|
171
171
|
alias_method :swap, :get_and_set
|
172
172
|
end
|
173
|
+
TruffleRubyAtomicReference
|
173
174
|
when Concurrent.on_rbx?
|
174
175
|
# @note Extends `Rubinius::AtomicReference` version adding aliases
|
175
176
|
# and numeric logic.
|
File without changes
|
@@ -19,7 +19,7 @@ module Concurrent
|
|
19
19
|
# t1 = Thread.new do
|
20
20
|
# puts "t1 is waiting"
|
21
21
|
# event.wait(1)
|
22
|
-
# puts "event
|
22
|
+
# puts "event occurred"
|
23
23
|
# end
|
24
24
|
#
|
25
25
|
# t2 = Thread.new do
|
@@ -30,8 +30,8 @@ module Concurrent
|
|
30
30
|
# [t1, t2].each(&:join)
|
31
31
|
#
|
32
32
|
# # prints:
|
33
|
-
# # t2 calling set
|
34
33
|
# # t1 is waiting
|
34
|
+
# # t2 calling set
|
35
35
|
# # event occurred
|
36
36
|
class Event < Synchronization::LockableObject
|
37
37
|
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -23,7 +23,14 @@ module Concurrent
|
|
23
23
|
|
24
24
|
synchronize do
|
25
25
|
try_acquire_timed(permits, nil)
|
26
|
-
|
26
|
+
end
|
27
|
+
|
28
|
+
return unless block_given?
|
29
|
+
|
30
|
+
begin
|
31
|
+
yield
|
32
|
+
ensure
|
33
|
+
release(permits)
|
27
34
|
end
|
28
35
|
end
|
29
36
|
|
@@ -48,13 +55,22 @@ module Concurrent
|
|
48
55
|
Utility::NativeInteger.ensure_integer_and_bounds permits
|
49
56
|
Utility::NativeInteger.ensure_positive permits
|
50
57
|
|
51
|
-
synchronize do
|
58
|
+
acquired = synchronize do
|
52
59
|
if timeout.nil?
|
53
60
|
try_acquire_now(permits)
|
54
61
|
else
|
55
62
|
try_acquire_timed(permits, timeout)
|
56
63
|
end
|
57
64
|
end
|
65
|
+
|
66
|
+
return acquired unless block_given?
|
67
|
+
return unless acquired
|
68
|
+
|
69
|
+
begin
|
70
|
+
yield
|
71
|
+
ensure
|
72
|
+
release(permits)
|
73
|
+
end
|
58
74
|
end
|
59
75
|
|
60
76
|
# @!macro semaphore_method_release
|
File without changes
|
@@ -267,12 +267,10 @@ module Concurrent
|
|
267
267
|
# running right now, AND no writers who came before us still waiting to
|
268
268
|
# acquire the lock
|
269
269
|
# Additionally, if any read locks have been taken, we must hold all of them
|
270
|
-
if
|
271
|
-
# If we successfully swap the RUNNING_WRITER bit on, then we can go ahead
|
272
|
-
|
273
|
-
|
274
|
-
return true
|
275
|
-
end
|
270
|
+
if held > 0 && @Counter.compare_and_set(1, c+RUNNING_WRITER)
|
271
|
+
# If we are the only one reader and successfully swap the RUNNING_WRITER bit on, then we can go ahead
|
272
|
+
@HeldCount.value = held + WRITE_LOCK_HELD
|
273
|
+
return true
|
276
274
|
elsif @Counter.compare_and_set(c, c+WAITING_WRITER)
|
277
275
|
while true
|
278
276
|
# Now we have successfully incremented, so no more readers will be able to increment
|
@@ -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,52 @@ 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
|
-
|
94
|
-
|
95
|
-
|
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
|
+
#
|
101
|
+
# DO NOT use each_value which might conflict with new pair assignment
|
102
|
+
# into the hash in #value= method
|
103
|
+
THREAD_LOCAL_ARRAYS.values.each { |array| array[index] = nil }
|
104
|
+
# free index has to be published after the arrays are cleared
|
105
|
+
FREE.push(index)
|
96
106
|
end
|
97
107
|
end
|
98
108
|
end
|
99
109
|
|
100
110
|
# @!visibility private
|
101
|
-
def self.thread_finalizer(
|
111
|
+
def self.thread_finalizer(id)
|
102
112
|
proc do
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
ARRAYS.delete(array.object_id)
|
108
|
-
end
|
113
|
+
semi_sync do
|
114
|
+
# The thread which used this thread-local array is now gone
|
115
|
+
# So don't hold onto a reference to the array (thus blocking GC)
|
116
|
+
THREAD_LOCAL_ARRAYS.delete(id)
|
109
117
|
end
|
110
118
|
end
|
111
119
|
end
|
112
120
|
|
113
121
|
private
|
114
122
|
|
123
|
+
# noinspection RubyClassVariableUsageInspection
|
124
|
+
@@next = 0
|
125
|
+
# noinspection RubyClassVariableUsageInspection
|
126
|
+
def next_index
|
127
|
+
LOCK.synchronize do
|
128
|
+
result = @@next
|
129
|
+
@@next += 1
|
130
|
+
result
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
115
134
|
if Thread.instance_methods.include?(:thread_variable_get)
|
116
135
|
|
117
136
|
def get_threadlocal_array(thread = Thread.current)
|
@@ -136,21 +155,22 @@ module Concurrent
|
|
136
155
|
# This exists only for use in testing
|
137
156
|
# @!visibility private
|
138
157
|
def value_for(thread)
|
139
|
-
if array = get_threadlocal_array(thread)
|
158
|
+
if (array = get_threadlocal_array(thread))
|
140
159
|
value = array[@index]
|
141
160
|
if value.nil?
|
142
|
-
|
161
|
+
get_default
|
143
162
|
elsif value.equal?(NULL)
|
144
163
|
nil
|
145
164
|
else
|
146
165
|
value
|
147
166
|
end
|
148
167
|
else
|
149
|
-
|
168
|
+
get_default
|
150
169
|
end
|
151
170
|
end
|
152
171
|
|
153
|
-
|
172
|
+
# @!visibility private
|
173
|
+
def get_default
|
154
174
|
if @default_block
|
155
175
|
raise "Cannot use default_for with default block"
|
156
176
|
else
|
@@ -16,14 +16,16 @@ module Concurrent
|
|
16
16
|
# @!macro semaphore_method_acquire
|
17
17
|
#
|
18
18
|
# Acquires the given number of permits from this semaphore,
|
19
|
-
# blocking until all are available.
|
19
|
+
# blocking until all are available. If a block is given,
|
20
|
+
# yields to it and releases the permits afterwards.
|
20
21
|
#
|
21
22
|
# @param [Fixnum] permits Number of permits to acquire
|
22
23
|
#
|
23
24
|
# @raise [ArgumentError] if `permits` is not an integer or is less than
|
24
25
|
# one
|
25
26
|
#
|
26
|
-
# @return [nil]
|
27
|
+
# @return [nil, BasicObject] Without a block, `nil` is returned. If a block
|
28
|
+
# is given, its return value is returned.
|
27
29
|
|
28
30
|
# @!macro semaphore_method_available_permits
|
29
31
|
#
|
@@ -41,7 +43,9 @@ module Concurrent
|
|
41
43
|
#
|
42
44
|
# Acquires the given number of permits from this semaphore,
|
43
45
|
# only if all are available at the time of invocation or within
|
44
|
-
# `timeout` interval
|
46
|
+
# `timeout` interval. If a block is given, yields to it if the permits
|
47
|
+
# were successfully acquired, and releases them afterward, returning the
|
48
|
+
# block's return value.
|
45
49
|
#
|
46
50
|
# @param [Fixnum] permits the number of permits to acquire
|
47
51
|
#
|
@@ -51,8 +55,10 @@ module Concurrent
|
|
51
55
|
# @raise [ArgumentError] if `permits` is not an integer or is less than
|
52
56
|
# one
|
53
57
|
#
|
54
|
-
# @return [
|
55
|
-
# acquired a permit
|
58
|
+
# @return [true, false, nil, BasicObject] `false` if no permits are
|
59
|
+
# available, `true` when acquired a permit. If a block is given, the
|
60
|
+
# block's return value is returned if the permits were acquired; if not,
|
61
|
+
# `nil` is returned.
|
56
62
|
|
57
63
|
# @!macro semaphore_method_release
|
58
64
|
#
|
@@ -106,6 +112,8 @@ module Concurrent
|
|
106
112
|
# releasing a blocking acquirer.
|
107
113
|
# However, no actual permit objects are used; the Semaphore just keeps a
|
108
114
|
# count of the number available and acts accordingly.
|
115
|
+
# Alternatively, permits may be acquired within a block, and automatically
|
116
|
+
# released after the block finishes executing.
|
109
117
|
#
|
110
118
|
# @!macro semaphore_public_api
|
111
119
|
# @example
|
@@ -140,6 +148,19 @@ module Concurrent
|
|
140
148
|
# # Thread 4 releasing semaphore
|
141
149
|
# # Thread 1 acquired semaphore
|
142
150
|
#
|
151
|
+
# @example
|
152
|
+
# semaphore = Concurrent::Semaphore.new(1)
|
153
|
+
#
|
154
|
+
# puts semaphore.available_permits
|
155
|
+
# semaphore.acquire do
|
156
|
+
# puts semaphore.available_permits
|
157
|
+
# end
|
158
|
+
# puts semaphore.available_permits
|
159
|
+
#
|
160
|
+
# # prints:
|
161
|
+
# # 1
|
162
|
+
# # 0
|
163
|
+
# # 1
|
143
164
|
class Semaphore < SemaphoreImplementation
|
144
165
|
end
|
145
166
|
end
|
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
|
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
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Concurrent
|
2
|
+
|
3
|
+
# @!visibility private
|
4
|
+
module Collection
|
5
|
+
|
6
|
+
# @!visibility private
|
7
|
+
class TruffleRubyMapBackend < TruffleRuby::ConcurrentMap
|
8
|
+
def initialize(options = nil)
|
9
|
+
options ||= {}
|
10
|
+
super(initial_capacity: options[:initial_capacity], load_factor: options[:load_factor])
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/{concurrent → concurrent-ruby/concurrent}/collection/ruby_non_concurrent_priority_queue.rb
RENAMED
@@ -30,7 +30,7 @@ module Concurrent
|
|
30
30
|
if @queue[k] == item
|
31
31
|
swap(k, @length)
|
32
32
|
@length -= 1
|
33
|
-
sink(k)
|
33
|
+
sink(k) || swim(k)
|
34
34
|
@queue.pop
|
35
35
|
else
|
36
36
|
k += 1
|
@@ -126,12 +126,17 @@ module Concurrent
|
|
126
126
|
#
|
127
127
|
# @!visibility private
|
128
128
|
def sink(k)
|
129
|
+
success = false
|
130
|
+
|
129
131
|
while (j = (2 * k)) <= @length do
|
130
132
|
j += 1 if j < @length && ! ordered?(j, j+1)
|
131
133
|
break if ordered?(k, j)
|
132
134
|
swap(k, j)
|
135
|
+
success = true
|
133
136
|
k = j
|
134
137
|
end
|
138
|
+
|
139
|
+
success
|
135
140
|
end
|
136
141
|
|
137
142
|
# Percolate up to maintain heap invariant.
|
@@ -140,10 +145,15 @@ module Concurrent
|
|
140
145
|
#
|
141
146
|
# @!visibility private
|
142
147
|
def swim(k)
|
148
|
+
success = false
|
149
|
+
|
143
150
|
while k > 1 && ! ordered?(k/2, k) do
|
144
151
|
swap(k, k/2)
|
145
152
|
k = k/2
|
153
|
+
success = true
|
146
154
|
end
|
155
|
+
|
156
|
+
success
|
147
157
|
end
|
148
158
|
end
|
149
159
|
end
|
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
|
File without changes
|
File without changes
|