concurrent-ruby 1.1.9 → 1.2.0
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 +24 -0
- data/Gemfile +2 -8
- data/README.md +34 -37
- data/Rakefile +48 -69
- 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/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +10 -25
- data/lib/concurrent-ruby/concurrent/agent.rb +2 -1
- data/lib/concurrent-ruby/concurrent/array.rb +0 -10
- data/lib/concurrent-ruby/concurrent/async.rb +1 -0
- data/lib/concurrent-ruby/concurrent/atom.rb +1 -1
- data/lib/concurrent-ruby/concurrent/atomic/atomic_boolean.rb +5 -4
- data/lib/concurrent-ruby/concurrent/atomic/atomic_fixnum.rb +5 -4
- data/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb +3 -0
- data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +82 -151
- data/lib/concurrent-ruby/concurrent/atomic/cyclic_barrier.rb +1 -1
- data/lib/concurrent-ruby/concurrent/atomic/event.rb +3 -3
- data/lib/concurrent-ruby/concurrent/atomic/fiber_local_var.rb +109 -0
- data/lib/concurrent-ruby/concurrent/atomic/java_count_down_latch.rb +1 -0
- data/lib/concurrent-ruby/concurrent/atomic/locals.rb +188 -0
- data/lib/concurrent-ruby/concurrent/atomic/lock_local_var.rb +28 -0
- data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_boolean.rb +11 -5
- data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb +11 -5
- data/lib/concurrent-ruby/concurrent/atomic/mutex_count_down_latch.rb +1 -1
- data/lib/concurrent-ruby/concurrent/atomic/mutex_semaphore.rb +19 -3
- data/lib/concurrent-ruby/concurrent/atomic/read_write_lock.rb +2 -1
- data/lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb +9 -9
- data/lib/concurrent-ruby/concurrent/atomic/semaphore.rb +32 -14
- data/lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb +96 -89
- data/lib/concurrent-ruby/concurrent/atomic_reference/atomic_direct_update.rb +37 -0
- data/lib/concurrent-ruby/concurrent/atomic_reference/mutex_atomic.rb +15 -4
- data/lib/concurrent-ruby/concurrent/collection/copy_on_notify_observer_set.rb +1 -1
- data/lib/concurrent-ruby/concurrent/collection/copy_on_write_observer_set.rb +1 -1
- data/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb +2 -0
- data/lib/concurrent-ruby/concurrent/concern/logging.rb +86 -2
- data/lib/concurrent-ruby/concurrent/concurrent_ruby.jar +0 -0
- data/lib/concurrent-ruby/concurrent/configuration.rb +4 -87
- data/lib/concurrent-ruby/concurrent/delay.rb +2 -2
- data/lib/concurrent-ruby/concurrent/errors.rb +5 -0
- data/lib/concurrent-ruby/concurrent/exchanger.rb +1 -0
- data/lib/concurrent-ruby/concurrent/executor/abstract_executor_service.rb +17 -14
- data/lib/concurrent-ruby/concurrent/executor/fixed_thread_pool.rb +13 -3
- data/lib/concurrent-ruby/concurrent/executor/java_executor_service.rb +3 -3
- data/lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb +4 -0
- data/lib/concurrent-ruby/concurrent/executor/ruby_executor_service.rb +10 -4
- data/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb +26 -37
- data/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb +6 -6
- data/lib/concurrent-ruby/concurrent/executor/serialized_execution.rb +1 -1
- data/lib/concurrent-ruby/concurrent/executor/simple_executor_service.rb +4 -1
- data/lib/concurrent-ruby/concurrent/hash.rb +0 -9
- data/lib/concurrent-ruby/concurrent/immutable_struct.rb +1 -1
- data/lib/concurrent-ruby/concurrent/ivar.rb +2 -1
- data/lib/concurrent-ruby/concurrent/map.rb +9 -9
- data/lib/concurrent-ruby/concurrent/maybe.rb +1 -1
- data/lib/concurrent-ruby/concurrent/mutable_struct.rb +1 -1
- data/lib/concurrent-ruby/concurrent/mvar.rb +1 -1
- data/lib/concurrent-ruby/concurrent/promise.rb +1 -1
- data/lib/concurrent-ruby/concurrent/promises.rb +7 -6
- data/lib/concurrent-ruby/concurrent/re_include.rb +2 -0
- data/lib/concurrent-ruby/concurrent/scheduled_task.rb +30 -17
- data/lib/concurrent-ruby/concurrent/set.rb +0 -10
- data/lib/concurrent-ruby/concurrent/settable_struct.rb +2 -2
- data/lib/concurrent-ruby/concurrent/synchronization/abstract_lockable_object.rb +5 -1
- data/lib/concurrent-ruby/concurrent/synchronization/abstract_object.rb +1 -3
- data/lib/concurrent-ruby/concurrent/synchronization/condition.rb +2 -0
- data/lib/concurrent-ruby/concurrent/synchronization/full_memory_barrier.rb +29 -0
- data/lib/concurrent-ruby/concurrent/synchronization/jruby_lockable_object.rb +3 -1
- data/lib/concurrent-ruby/concurrent/synchronization/lock.rb +2 -0
- data/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb +6 -5
- data/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb +6 -5
- data/lib/concurrent-ruby/concurrent/synchronization/object.rb +12 -44
- data/lib/concurrent-ruby/concurrent/synchronization/safe_initialization.rb +36 -0
- data/lib/concurrent-ruby/concurrent/synchronization/volatile.rb +77 -12
- data/lib/concurrent-ruby/concurrent/synchronization.rb +1 -18
- data/lib/concurrent-ruby/concurrent/thread_safe/synchronized_delegator.rb +36 -39
- data/lib/concurrent-ruby/concurrent/thread_safe/util/cheap_lockable.rb +2 -39
- data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +1 -37
- data/lib/concurrent-ruby/concurrent/timer_task.rb +11 -33
- data/lib/concurrent-ruby/concurrent/tuple.rb +1 -5
- data/lib/concurrent-ruby/concurrent/tvar.rb +22 -61
- data/lib/concurrent-ruby/concurrent/utility/engine.rb +5 -16
- data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +7 -46
- data/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb +8 -10
- data/lib/concurrent-ruby/concurrent/utility/native_integer.rb +1 -0
- data/lib/concurrent-ruby/concurrent/utility/processor_counter.rb +36 -89
- data/lib/concurrent-ruby/concurrent/version.rb +1 -1
- data/lib/concurrent-ruby/concurrent-ruby.rb +5 -1
- metadata +10 -12
- data/lib/concurrent-ruby/concurrent/atomic/abstract_thread_local_var.rb +0 -66
- data/lib/concurrent-ruby/concurrent/atomic/java_thread_local_var.rb +0 -37
- data/lib/concurrent-ruby/concurrent/atomic/ruby_thread_local_var.rb +0 -181
- data/lib/concurrent-ruby/concurrent/synchronization/jruby_object.rb +0 -45
- data/lib/concurrent-ruby/concurrent/synchronization/mri_object.rb +0 -44
- data/lib/concurrent-ruby/concurrent/synchronization/rbx_lockable_object.rb +0 -71
- data/lib/concurrent-ruby/concurrent/synchronization/rbx_object.rb +0 -49
- data/lib/concurrent-ruby/concurrent/synchronization/truffleruby_object.rb +0 -47
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'logger'
|
2
|
+
require 'concurrent/atomic/atomic_reference'
|
2
3
|
|
3
4
|
module Concurrent
|
4
5
|
module Concern
|
@@ -15,8 +16,6 @@ module Concurrent
|
|
15
16
|
# @param [String, nil] message when nil block is used to generate the message
|
16
17
|
# @yieldreturn [String] a message
|
17
18
|
def log(level, progname, message = nil, &block)
|
18
|
-
#NOTE: Cannot require 'concurrent/configuration' above due to circular references.
|
19
|
-
# Assume that the gem has been initialized if we've gotten this far.
|
20
19
|
logger = if defined?(@logger) && @logger
|
21
20
|
@logger
|
22
21
|
else
|
@@ -30,3 +29,88 @@ module Concurrent
|
|
30
29
|
end
|
31
30
|
end
|
32
31
|
end
|
32
|
+
|
33
|
+
module Concurrent
|
34
|
+
extend Concern::Logging
|
35
|
+
|
36
|
+
# @return [Logger] Logger with provided level and output.
|
37
|
+
def self.create_simple_logger(level = Logger::FATAL, output = $stderr)
|
38
|
+
# TODO (pitr-ch 24-Dec-2016): figure out why it had to be replaced, stdlogger was deadlocking
|
39
|
+
lambda do |severity, progname, message = nil, &block|
|
40
|
+
return false if severity < level
|
41
|
+
|
42
|
+
message = block ? block.call : message
|
43
|
+
formatted_message = case message
|
44
|
+
when String
|
45
|
+
message
|
46
|
+
when Exception
|
47
|
+
format "%s (%s)\n%s",
|
48
|
+
message.message, message.class, (message.backtrace || []).join("\n")
|
49
|
+
else
|
50
|
+
message.inspect
|
51
|
+
end
|
52
|
+
|
53
|
+
output.print format "[%s] %5s -- %s: %s\n",
|
54
|
+
Time.now.strftime('%Y-%m-%d %H:%M:%S.%L'),
|
55
|
+
Logger::SEV_LABEL[severity],
|
56
|
+
progname,
|
57
|
+
formatted_message
|
58
|
+
true
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Use logger created by #create_simple_logger to log concurrent-ruby messages.
|
63
|
+
def self.use_simple_logger(level = Logger::FATAL, output = $stderr)
|
64
|
+
Concurrent.global_logger = create_simple_logger level, output
|
65
|
+
end
|
66
|
+
|
67
|
+
# @return [Logger] Logger with provided level and output.
|
68
|
+
# @deprecated
|
69
|
+
def self.create_stdlib_logger(level = Logger::FATAL, output = $stderr)
|
70
|
+
logger = Logger.new(output)
|
71
|
+
logger.level = level
|
72
|
+
logger.formatter = lambda do |severity, datetime, progname, msg|
|
73
|
+
formatted_message = case msg
|
74
|
+
when String
|
75
|
+
msg
|
76
|
+
when Exception
|
77
|
+
format "%s (%s)\n%s",
|
78
|
+
msg.message, msg.class, (msg.backtrace || []).join("\n")
|
79
|
+
else
|
80
|
+
msg.inspect
|
81
|
+
end
|
82
|
+
format "[%s] %5s -- %s: %s\n",
|
83
|
+
datetime.strftime('%Y-%m-%d %H:%M:%S.%L'),
|
84
|
+
severity,
|
85
|
+
progname,
|
86
|
+
formatted_message
|
87
|
+
end
|
88
|
+
|
89
|
+
lambda do |loglevel, progname, message = nil, &block|
|
90
|
+
logger.add loglevel, message, progname, &block
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Use logger created by #create_stdlib_logger to log concurrent-ruby messages.
|
95
|
+
# @deprecated
|
96
|
+
def self.use_stdlib_logger(level = Logger::FATAL, output = $stderr)
|
97
|
+
Concurrent.global_logger = create_stdlib_logger level, output
|
98
|
+
end
|
99
|
+
|
100
|
+
# TODO (pitr-ch 27-Dec-2016): remove deadlocking stdlib_logger methods
|
101
|
+
|
102
|
+
# Suppresses all output when used for logging.
|
103
|
+
NULL_LOGGER = lambda { |level, progname, message = nil, &block| }
|
104
|
+
|
105
|
+
# @!visibility private
|
106
|
+
GLOBAL_LOGGER = AtomicReference.new(create_simple_logger(Logger::WARN))
|
107
|
+
private_constant :GLOBAL_LOGGER
|
108
|
+
|
109
|
+
def self.global_logger
|
110
|
+
GLOBAL_LOGGER.value
|
111
|
+
end
|
112
|
+
|
113
|
+
def self.global_logger=(value)
|
114
|
+
GLOBAL_LOGGER.value = value
|
115
|
+
end
|
116
|
+
end
|
Binary file
|
@@ -1,102 +1,19 @@
|
|
1
1
|
require 'thread'
|
2
2
|
require 'concurrent/delay'
|
3
3
|
require 'concurrent/errors'
|
4
|
-
require 'concurrent/atomic/atomic_reference'
|
5
|
-
require 'concurrent/concern/logging'
|
6
4
|
require 'concurrent/concern/deprecation'
|
7
5
|
require 'concurrent/executor/immediate_executor'
|
6
|
+
require 'concurrent/executor/fixed_thread_pool'
|
8
7
|
require 'concurrent/executor/cached_thread_pool'
|
9
8
|
require 'concurrent/utility/processor_counter'
|
10
9
|
|
11
10
|
module Concurrent
|
12
|
-
extend Concern::Logging
|
13
11
|
extend Concern::Deprecation
|
14
12
|
|
15
13
|
autoload :Options, 'concurrent/options'
|
16
14
|
autoload :TimerSet, 'concurrent/executor/timer_set'
|
17
15
|
autoload :ThreadPoolExecutor, 'concurrent/executor/thread_pool_executor'
|
18
16
|
|
19
|
-
# @return [Logger] Logger with provided level and output.
|
20
|
-
def self.create_simple_logger(level = Logger::FATAL, output = $stderr)
|
21
|
-
# TODO (pitr-ch 24-Dec-2016): figure out why it had to be replaced, stdlogger was deadlocking
|
22
|
-
lambda do |severity, progname, message = nil, &block|
|
23
|
-
return false if severity < level
|
24
|
-
|
25
|
-
message = block ? block.call : message
|
26
|
-
formatted_message = case message
|
27
|
-
when String
|
28
|
-
message
|
29
|
-
when Exception
|
30
|
-
format "%s (%s)\n%s",
|
31
|
-
message.message, message.class, (message.backtrace || []).join("\n")
|
32
|
-
else
|
33
|
-
message.inspect
|
34
|
-
end
|
35
|
-
|
36
|
-
output.print format "[%s] %5s -- %s: %s\n",
|
37
|
-
Time.now.strftime('%Y-%m-%d %H:%M:%S.%L'),
|
38
|
-
Logger::SEV_LABEL[severity],
|
39
|
-
progname,
|
40
|
-
formatted_message
|
41
|
-
true
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
# Use logger created by #create_simple_logger to log concurrent-ruby messages.
|
46
|
-
def self.use_simple_logger(level = Logger::FATAL, output = $stderr)
|
47
|
-
Concurrent.global_logger = create_simple_logger level, output
|
48
|
-
end
|
49
|
-
|
50
|
-
# @return [Logger] Logger with provided level and output.
|
51
|
-
# @deprecated
|
52
|
-
def self.create_stdlib_logger(level = Logger::FATAL, output = $stderr)
|
53
|
-
logger = Logger.new(output)
|
54
|
-
logger.level = level
|
55
|
-
logger.formatter = lambda do |severity, datetime, progname, msg|
|
56
|
-
formatted_message = case msg
|
57
|
-
when String
|
58
|
-
msg
|
59
|
-
when Exception
|
60
|
-
format "%s (%s)\n%s",
|
61
|
-
msg.message, msg.class, (msg.backtrace || []).join("\n")
|
62
|
-
else
|
63
|
-
msg.inspect
|
64
|
-
end
|
65
|
-
format "[%s] %5s -- %s: %s\n",
|
66
|
-
datetime.strftime('%Y-%m-%d %H:%M:%S.%L'),
|
67
|
-
severity,
|
68
|
-
progname,
|
69
|
-
formatted_message
|
70
|
-
end
|
71
|
-
|
72
|
-
lambda do |loglevel, progname, message = nil, &block|
|
73
|
-
logger.add loglevel, message, progname, &block
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
# Use logger created by #create_stdlib_logger to log concurrent-ruby messages.
|
78
|
-
# @deprecated
|
79
|
-
def self.use_stdlib_logger(level = Logger::FATAL, output = $stderr)
|
80
|
-
Concurrent.global_logger = create_stdlib_logger level, output
|
81
|
-
end
|
82
|
-
|
83
|
-
# TODO (pitr-ch 27-Dec-2016): remove deadlocking stdlib_logger methods
|
84
|
-
|
85
|
-
# Suppresses all output when used for logging.
|
86
|
-
NULL_LOGGER = lambda { |level, progname, message = nil, &block| }
|
87
|
-
|
88
|
-
# @!visibility private
|
89
|
-
GLOBAL_LOGGER = AtomicReference.new(create_simple_logger(Logger::WARN))
|
90
|
-
private_constant :GLOBAL_LOGGER
|
91
|
-
|
92
|
-
def self.global_logger
|
93
|
-
GLOBAL_LOGGER.value
|
94
|
-
end
|
95
|
-
|
96
|
-
def self.global_logger=(value)
|
97
|
-
GLOBAL_LOGGER.value = value
|
98
|
-
end
|
99
|
-
|
100
17
|
# @!visibility private
|
101
18
|
GLOBAL_FAST_EXECUTOR = Delay.new { Concurrent.new_fast_executor }
|
102
19
|
private_constant :GLOBAL_FAST_EXECUTOR
|
@@ -136,14 +53,14 @@ module Concurrent
|
|
136
53
|
#
|
137
54
|
# @return [ThreadPoolExecutor] the thread pool
|
138
55
|
def self.global_fast_executor
|
139
|
-
GLOBAL_FAST_EXECUTOR.value
|
56
|
+
GLOBAL_FAST_EXECUTOR.value!
|
140
57
|
end
|
141
58
|
|
142
59
|
# Global thread pool optimized for long, blocking (IO) *tasks*.
|
143
60
|
#
|
144
61
|
# @return [ThreadPoolExecutor] the thread pool
|
145
62
|
def self.global_io_executor
|
146
|
-
GLOBAL_IO_EXECUTOR.value
|
63
|
+
GLOBAL_IO_EXECUTOR.value!
|
147
64
|
end
|
148
65
|
|
149
66
|
def self.global_immediate_executor
|
@@ -154,7 +71,7 @@ module Concurrent
|
|
154
71
|
#
|
155
72
|
# @return [Concurrent::TimerSet] the thread pool
|
156
73
|
def self.global_timer_set
|
157
|
-
GLOBAL_TIMER_SET.value
|
74
|
+
GLOBAL_TIMER_SET.value!
|
158
75
|
end
|
159
76
|
|
160
77
|
# General access point to global executors.
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'thread'
|
2
2
|
require 'concurrent/concern/obligation'
|
3
3
|
require 'concurrent/executor/immediate_executor'
|
4
|
-
require 'concurrent/synchronization'
|
4
|
+
require 'concurrent/synchronization/lockable_object'
|
5
5
|
|
6
6
|
module Concurrent
|
7
7
|
|
@@ -67,7 +67,7 @@ module Concurrent
|
|
67
67
|
|
68
68
|
# Return the value this object represents after applying the options
|
69
69
|
# specified by the `#set_deref_options` method. If the delayed operation
|
70
|
-
# raised an exception this method will return nil. The
|
70
|
+
# raised an exception this method will return nil. The exception object
|
71
71
|
# can be accessed via the `#reason` method.
|
72
72
|
#
|
73
73
|
# @param [Numeric] timeout the maximum number of seconds to wait
|
@@ -66,4 +66,9 @@ module Concurrent
|
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
|
+
# @!macro internal_implementation_note
|
70
|
+
class ConcurrentUpdateError < ThreadError
|
71
|
+
# frozen pre-allocated backtrace to speed ConcurrentUpdateError
|
72
|
+
CONC_UP_ERR_BACKTRACE = ['backtrace elided; set verbose to enable'].freeze
|
73
|
+
end
|
69
74
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'concurrent/errors'
|
2
2
|
require 'concurrent/concern/deprecation'
|
3
3
|
require 'concurrent/executor/executor_service'
|
4
|
-
require 'concurrent/synchronization'
|
4
|
+
require 'concurrent/synchronization/lockable_object'
|
5
5
|
|
6
6
|
module Concurrent
|
7
7
|
|
@@ -75,28 +75,31 @@ module Concurrent
|
|
75
75
|
|
76
76
|
private
|
77
77
|
|
78
|
-
#
|
79
|
-
# reaches `max_queue`.
|
78
|
+
# Returns an action which executes the `fallback_policy` once the queue
|
79
|
+
# size reaches `max_queue`. The reason for the indirection of an action
|
80
|
+
# is so that the work can be deferred outside of synchronization.
|
80
81
|
#
|
81
82
|
# @param [Array] args the arguments to the task which is being handled.
|
82
83
|
#
|
83
84
|
# @!visibility private
|
84
|
-
def
|
85
|
+
def fallback_action(*args)
|
85
86
|
case fallback_policy
|
86
87
|
when :abort
|
87
|
-
raise RejectedExecutionError
|
88
|
+
lambda { raise RejectedExecutionError }
|
88
89
|
when :discard
|
89
|
-
false
|
90
|
+
lambda { false }
|
90
91
|
when :caller_runs
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
92
|
+
lambda {
|
93
|
+
begin
|
94
|
+
yield(*args)
|
95
|
+
rescue => ex
|
96
|
+
# let it fail
|
97
|
+
log DEBUG, ex
|
98
|
+
end
|
99
|
+
true
|
100
|
+
}
|
98
101
|
else
|
99
|
-
fail "Unknown fallback policy #{fallback_policy}"
|
102
|
+
lambda { fail "Unknown fallback policy #{fallback_policy}" }
|
100
103
|
end
|
101
104
|
end
|
102
105
|
|
@@ -71,9 +71,16 @@ module Concurrent
|
|
71
71
|
# @return [Integer] Number of tasks that may be enqueued before reaching `max_queue` and rejecting
|
72
72
|
# new tasks. A value of -1 indicates that the queue may grow without bound.
|
73
73
|
|
74
|
-
|
75
|
-
|
76
|
-
|
74
|
+
# @!macro thread_pool_executor_method_prune_pool
|
75
|
+
# Prune the thread pool of unneeded threads
|
76
|
+
#
|
77
|
+
# What is being pruned is controlled by the min_threads and idletime
|
78
|
+
# parameters passed at pool creation time
|
79
|
+
#
|
80
|
+
# This is a no-op on some pool implementation (e.g. the Java one). The Ruby
|
81
|
+
# pool will auto-prune each time a new job is posted. You will need to call
|
82
|
+
# this method explicitely in case your application post jobs in bursts (a
|
83
|
+
# lot of jobs and then nothing for long periods)
|
77
84
|
|
78
85
|
# @!macro thread_pool_executor_public_api
|
79
86
|
#
|
@@ -111,6 +118,9 @@ module Concurrent
|
|
111
118
|
#
|
112
119
|
# @!method can_overflow?
|
113
120
|
# @!macro executor_service_method_can_overflow_question
|
121
|
+
#
|
122
|
+
# @!method prune_pool
|
123
|
+
# @!macro thread_pool_executor_method_prune_pool
|
114
124
|
|
115
125
|
|
116
126
|
|
@@ -1,7 +1,7 @@
|
|
1
|
-
|
1
|
+
require 'concurrent/utility/engine'
|
2
2
|
|
3
|
+
if Concurrent.on_jruby?
|
3
4
|
require 'concurrent/errors'
|
4
|
-
require 'concurrent/utility/engine'
|
5
5
|
require 'concurrent/executor/abstract_executor_service'
|
6
6
|
|
7
7
|
module Concurrent
|
@@ -20,7 +20,7 @@ if Concurrent.on_jruby?
|
|
20
20
|
|
21
21
|
def post(*args, &task)
|
22
22
|
raise ArgumentError.new('no block given') unless block_given?
|
23
|
-
return
|
23
|
+
return fallback_action(*args, &task).call unless running?
|
24
24
|
@executor.submit Job.new(args, task)
|
25
25
|
true
|
26
26
|
rescue Java::JavaUtilConcurrent::RejectedExecutionException
|
@@ -16,10 +16,16 @@ module Concurrent
|
|
16
16
|
|
17
17
|
def post(*args, &task)
|
18
18
|
raise ArgumentError.new('no block given') unless block_given?
|
19
|
-
synchronize
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
deferred_action = synchronize {
|
20
|
+
if running?
|
21
|
+
ns_execute(*args, &task)
|
22
|
+
else
|
23
|
+
fallback_action(*args, &task)
|
24
|
+
end
|
25
|
+
}
|
26
|
+
if deferred_action
|
27
|
+
deferred_action.call
|
28
|
+
else
|
23
29
|
true
|
24
30
|
end
|
25
31
|
end
|
@@ -93,13 +93,8 @@ module Concurrent
|
|
93
93
|
end
|
94
94
|
|
95
95
|
# @!visibility private
|
96
|
-
def ready_worker(worker)
|
97
|
-
synchronize { ns_ready_worker worker }
|
98
|
-
end
|
99
|
-
|
100
|
-
# @!visibility private
|
101
|
-
def worker_not_old_enough(worker)
|
102
|
-
synchronize { ns_worker_not_old_enough worker }
|
96
|
+
def ready_worker(worker, last_message)
|
97
|
+
synchronize { ns_ready_worker worker, last_message }
|
103
98
|
end
|
104
99
|
|
105
100
|
# @!visibility private
|
@@ -112,6 +107,11 @@ module Concurrent
|
|
112
107
|
synchronize { @completed_task_count += 1 }
|
113
108
|
end
|
114
109
|
|
110
|
+
# @!macro thread_pool_executor_method_prune_pool
|
111
|
+
def prune_pool
|
112
|
+
synchronize { ns_prune_pool }
|
113
|
+
end
|
114
|
+
|
115
115
|
private
|
116
116
|
|
117
117
|
# @!visibility private
|
@@ -156,10 +156,11 @@ module Concurrent
|
|
156
156
|
if ns_assign_worker(*args, &task) || ns_enqueue(*args, &task)
|
157
157
|
@scheduled_task_count += 1
|
158
158
|
else
|
159
|
-
|
159
|
+
return fallback_action(*args, &task)
|
160
160
|
end
|
161
161
|
|
162
162
|
ns_prune_pool if @next_gc_time < Concurrent.monotonic_time
|
163
|
+
nil
|
163
164
|
end
|
164
165
|
|
165
166
|
# @!visibility private
|
@@ -192,7 +193,7 @@ module Concurrent
|
|
192
193
|
# @!visibility private
|
193
194
|
def ns_assign_worker(*args, &task)
|
194
195
|
# keep growing if the pool is not at the minimum yet
|
195
|
-
worker = (@ready.pop if @pool.size >= @min_length) || ns_add_busy_worker
|
196
|
+
worker, _ = (@ready.pop if @pool.size >= @min_length) || ns_add_busy_worker
|
196
197
|
if worker
|
197
198
|
worker << [task, args]
|
198
199
|
true
|
@@ -223,7 +224,7 @@ module Concurrent
|
|
223
224
|
def ns_worker_died(worker)
|
224
225
|
ns_remove_busy_worker worker
|
225
226
|
replacement_worker = ns_add_busy_worker
|
226
|
-
ns_ready_worker replacement_worker, false if replacement_worker
|
227
|
+
ns_ready_worker replacement_worker, Concurrent.monotonic_time, false if replacement_worker
|
227
228
|
end
|
228
229
|
|
229
230
|
# creates new worker which has to receive work to do after it's added
|
@@ -242,29 +243,21 @@ module Concurrent
|
|
242
243
|
# handle ready worker, giving it new job or assigning back to @ready
|
243
244
|
#
|
244
245
|
# @!visibility private
|
245
|
-
def ns_ready_worker(worker, success = true)
|
246
|
+
def ns_ready_worker(worker, last_message, success = true)
|
246
247
|
task_and_args = @queue.shift
|
247
248
|
if task_and_args
|
248
249
|
worker << task_and_args
|
249
250
|
else
|
250
251
|
# stop workers when !running?, do not return them to @ready
|
251
252
|
if running?
|
252
|
-
|
253
|
+
raise unless last_message
|
254
|
+
@ready.push([worker, last_message])
|
253
255
|
else
|
254
256
|
worker.stop
|
255
257
|
end
|
256
258
|
end
|
257
259
|
end
|
258
260
|
|
259
|
-
# returns back worker to @ready which was not idle for enough time
|
260
|
-
#
|
261
|
-
# @!visibility private
|
262
|
-
def ns_worker_not_old_enough(worker)
|
263
|
-
# let's put workers coming from idle_test back to the start (as the oldest worker)
|
264
|
-
@ready.unshift(worker)
|
265
|
-
true
|
266
|
-
end
|
267
|
-
|
268
261
|
# removes a worker which is not in not tracked in @ready
|
269
262
|
#
|
270
263
|
# @!visibility private
|
@@ -278,10 +271,17 @@ module Concurrent
|
|
278
271
|
#
|
279
272
|
# @!visibility private
|
280
273
|
def ns_prune_pool
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
274
|
+
now = Concurrent.monotonic_time
|
275
|
+
stopped_workers = 0
|
276
|
+
while !@ready.empty? && (@pool.size - stopped_workers > @min_length)
|
277
|
+
worker, last_message = @ready.first
|
278
|
+
if now - last_message > self.idletime
|
279
|
+
stopped_workers += 1
|
280
|
+
@ready.shift
|
281
|
+
worker << :stop
|
282
|
+
else break
|
283
|
+
end
|
284
|
+
end
|
285
285
|
|
286
286
|
@next_gc_time = Concurrent.monotonic_time + @gc_interval
|
287
287
|
end
|
@@ -330,19 +330,10 @@ module Concurrent
|
|
330
330
|
|
331
331
|
def create_worker(queue, pool, idletime)
|
332
332
|
Thread.new(queue, pool, idletime) do |my_queue, my_pool, my_idletime|
|
333
|
-
last_message = Concurrent.monotonic_time
|
334
333
|
catch(:stop) do
|
335
334
|
loop do
|
336
335
|
|
337
336
|
case message = my_queue.pop
|
338
|
-
when :idle_test
|
339
|
-
if (Concurrent.monotonic_time - last_message) > my_idletime
|
340
|
-
my_pool.remove_busy_worker(self)
|
341
|
-
throw :stop
|
342
|
-
else
|
343
|
-
my_pool.worker_not_old_enough(self)
|
344
|
-
end
|
345
|
-
|
346
337
|
when :stop
|
347
338
|
my_pool.remove_busy_worker(self)
|
348
339
|
throw :stop
|
@@ -350,9 +341,7 @@ module Concurrent
|
|
350
341
|
else
|
351
342
|
task, args = message
|
352
343
|
run_task my_pool, task, args
|
353
|
-
|
354
|
-
|
355
|
-
my_pool.ready_worker(self)
|
344
|
+
my_pool.ready_worker(self, Concurrent.monotonic_time)
|
356
345
|
end
|
357
346
|
end
|
358
347
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'concurrent/synchronization'
|
1
|
+
require 'concurrent/synchronization/lockable_object'
|
2
2
|
|
3
3
|
module Concurrent
|
4
4
|
|
@@ -16,10 +16,10 @@ module Concurrent
|
|
16
16
|
|
17
17
|
# @return [Array]
|
18
18
|
def execute(*args)
|
19
|
-
|
20
|
-
|
21
|
-
value = reason = nil
|
19
|
+
success = true
|
20
|
+
value = reason = nil
|
22
21
|
|
22
|
+
synchronize do
|
23
23
|
begin
|
24
24
|
value = @task.call(*args)
|
25
25
|
success = true
|
@@ -27,9 +27,9 @@ module Concurrent
|
|
27
27
|
reason = ex
|
28
28
|
success = false
|
29
29
|
end
|
30
|
-
|
31
|
-
[success, value, reason]
|
32
30
|
end
|
31
|
+
|
32
|
+
[success, value, reason]
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|
@@ -1,5 +1,8 @@
|
|
1
|
-
require 'concurrent/
|
1
|
+
require 'concurrent/atomic/atomic_boolean'
|
2
|
+
require 'concurrent/atomic/atomic_fixnum'
|
3
|
+
require 'concurrent/atomic/event'
|
2
4
|
require 'concurrent/executor/executor_service'
|
5
|
+
require 'concurrent/executor/ruby_executor_service'
|
3
6
|
|
4
7
|
module Concurrent
|
5
8
|
|
@@ -28,15 +28,6 @@ module Concurrent
|
|
28
28
|
end
|
29
29
|
JRubyHash
|
30
30
|
|
31
|
-
when Concurrent.on_rbx?
|
32
|
-
require 'monitor'
|
33
|
-
require 'concurrent/thread_safe/util/data_structures'
|
34
|
-
|
35
|
-
class RbxHash < ::Hash
|
36
|
-
end
|
37
|
-
ThreadSafe::Util.make_synchronized_on_rbx RbxHash
|
38
|
-
RbxHash
|
39
|
-
|
40
31
|
when Concurrent.on_truffleruby?
|
41
32
|
require 'concurrent/thread_safe/util/data_structures'
|
42
33
|
|
@@ -3,7 +3,8 @@ require 'concurrent/errors'
|
|
3
3
|
require 'concurrent/collection/copy_on_write_observer_set'
|
4
4
|
require 'concurrent/concern/obligation'
|
5
5
|
require 'concurrent/concern/observable'
|
6
|
-
require 'concurrent/
|
6
|
+
require 'concurrent/executor/safe_task_executor'
|
7
|
+
require 'concurrent/synchronization/lockable_object'
|
7
8
|
|
8
9
|
module Concurrent
|
9
10
|
|