concurrent-ruby 0.7.0-java
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.
- data/LICENSE.txt +21 -0
- data/README.md +217 -0
- data/lib/concurrent.rb +45 -0
- data/lib/concurrent/actor.rb +104 -0
- data/lib/concurrent/actor/behaviour.rb +70 -0
- data/lib/concurrent/actor/behaviour/abstract.rb +48 -0
- data/lib/concurrent/actor/behaviour/awaits.rb +21 -0
- data/lib/concurrent/actor/behaviour/buffer.rb +54 -0
- data/lib/concurrent/actor/behaviour/errors_on_unknown_message.rb +12 -0
- data/lib/concurrent/actor/behaviour/executes_context.rb +18 -0
- data/lib/concurrent/actor/behaviour/linking.rb +42 -0
- data/lib/concurrent/actor/behaviour/pausing.rb +77 -0
- data/lib/concurrent/actor/behaviour/removes_child.rb +16 -0
- data/lib/concurrent/actor/behaviour/sets_results.rb +36 -0
- data/lib/concurrent/actor/behaviour/supervised.rb +58 -0
- data/lib/concurrent/actor/behaviour/supervising.rb +34 -0
- data/lib/concurrent/actor/behaviour/terminates_children.rb +13 -0
- data/lib/concurrent/actor/behaviour/termination.rb +54 -0
- data/lib/concurrent/actor/context.rb +153 -0
- data/lib/concurrent/actor/core.rb +213 -0
- data/lib/concurrent/actor/default_dead_letter_handler.rb +9 -0
- data/lib/concurrent/actor/envelope.rb +41 -0
- data/lib/concurrent/actor/errors.rb +27 -0
- data/lib/concurrent/actor/internal_delegations.rb +49 -0
- data/lib/concurrent/actor/public_delegations.rb +40 -0
- data/lib/concurrent/actor/reference.rb +81 -0
- data/lib/concurrent/actor/root.rb +37 -0
- data/lib/concurrent/actor/type_check.rb +48 -0
- data/lib/concurrent/actor/utils.rb +10 -0
- data/lib/concurrent/actor/utils/ad_hoc.rb +21 -0
- data/lib/concurrent/actor/utils/balancer.rb +40 -0
- data/lib/concurrent/actor/utils/broadcast.rb +52 -0
- data/lib/concurrent/actor/utils/pool.rb +59 -0
- data/lib/concurrent/actress.rb +3 -0
- data/lib/concurrent/agent.rb +230 -0
- data/lib/concurrent/async.rb +284 -0
- data/lib/concurrent/atomic.rb +91 -0
- data/lib/concurrent/atomic/atomic_boolean.rb +202 -0
- data/lib/concurrent/atomic/atomic_fixnum.rb +203 -0
- data/lib/concurrent/atomic/condition.rb +67 -0
- data/lib/concurrent/atomic/copy_on_notify_observer_set.rb +118 -0
- data/lib/concurrent/atomic/copy_on_write_observer_set.rb +117 -0
- data/lib/concurrent/atomic/count_down_latch.rb +116 -0
- data/lib/concurrent/atomic/cyclic_barrier.rb +106 -0
- data/lib/concurrent/atomic/event.rb +98 -0
- data/lib/concurrent/atomic/synchronization.rb +51 -0
- data/lib/concurrent/atomic/thread_local_var.rb +82 -0
- data/lib/concurrent/atomic_reference/concurrent_update_error.rb +8 -0
- data/lib/concurrent/atomic_reference/direct_update.rb +50 -0
- data/lib/concurrent/atomic_reference/jruby.rb +14 -0
- data/lib/concurrent/atomic_reference/mutex_atomic.rb +77 -0
- data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +25 -0
- data/lib/concurrent/atomic_reference/rbx.rb +19 -0
- data/lib/concurrent/atomic_reference/ruby.rb +37 -0
- data/lib/concurrent/atomics.rb +11 -0
- data/lib/concurrent/channel/buffered_channel.rb +85 -0
- data/lib/concurrent/channel/channel.rb +41 -0
- data/lib/concurrent/channel/unbuffered_channel.rb +35 -0
- data/lib/concurrent/channel/waitable_list.rb +40 -0
- data/lib/concurrent/channels.rb +5 -0
- data/lib/concurrent/collection/blocking_ring_buffer.rb +71 -0
- data/lib/concurrent/collection/priority_queue.rb +305 -0
- data/lib/concurrent/collection/ring_buffer.rb +59 -0
- data/lib/concurrent/collections.rb +3 -0
- data/lib/concurrent/configuration.rb +161 -0
- data/lib/concurrent/dataflow.rb +108 -0
- data/lib/concurrent/delay.rb +104 -0
- data/lib/concurrent/dereferenceable.rb +101 -0
- data/lib/concurrent/errors.rb +30 -0
- data/lib/concurrent/exchanger.rb +34 -0
- data/lib/concurrent/executor/cached_thread_pool.rb +44 -0
- data/lib/concurrent/executor/executor.rb +282 -0
- data/lib/concurrent/executor/fixed_thread_pool.rb +33 -0
- data/lib/concurrent/executor/immediate_executor.rb +65 -0
- data/lib/concurrent/executor/java_cached_thread_pool.rb +31 -0
- data/lib/concurrent/executor/java_fixed_thread_pool.rb +41 -0
- data/lib/concurrent/executor/java_single_thread_executor.rb +22 -0
- data/lib/concurrent/executor/java_thread_pool_executor.rb +180 -0
- data/lib/concurrent/executor/per_thread_executor.rb +100 -0
- data/lib/concurrent/executor/ruby_cached_thread_pool.rb +29 -0
- data/lib/concurrent/executor/ruby_fixed_thread_pool.rb +32 -0
- data/lib/concurrent/executor/ruby_single_thread_executor.rb +74 -0
- data/lib/concurrent/executor/ruby_thread_pool_executor.rb +288 -0
- data/lib/concurrent/executor/ruby_thread_pool_worker.rb +72 -0
- data/lib/concurrent/executor/safe_task_executor.rb +35 -0
- data/lib/concurrent/executor/serialized_execution.rb +126 -0
- data/lib/concurrent/executor/single_thread_executor.rb +35 -0
- data/lib/concurrent/executor/thread_pool_executor.rb +68 -0
- data/lib/concurrent/executor/timer_set.rb +143 -0
- data/lib/concurrent/executors.rb +9 -0
- data/lib/concurrent/future.rb +125 -0
- data/lib/concurrent/ivar.rb +111 -0
- data/lib/concurrent/lazy_register.rb +58 -0
- data/lib/concurrent/logging.rb +17 -0
- data/lib/concurrent/mvar.rb +200 -0
- data/lib/concurrent/obligation.rb +171 -0
- data/lib/concurrent/observable.rb +40 -0
- data/lib/concurrent/options_parser.rb +48 -0
- data/lib/concurrent/promise.rb +170 -0
- data/lib/concurrent/scheduled_task.rb +79 -0
- data/lib/concurrent/timer_task.rb +341 -0
- data/lib/concurrent/tvar.rb +248 -0
- data/lib/concurrent/utilities.rb +3 -0
- data/lib/concurrent/utility/processor_count.rb +152 -0
- data/lib/concurrent/utility/timeout.rb +35 -0
- data/lib/concurrent/utility/timer.rb +21 -0
- data/lib/concurrent/version.rb +3 -0
- data/lib/concurrent_ruby.rb +1 -0
- data/lib/concurrent_ruby_ext.jar +0 -0
- data/lib/concurrent_ruby_ext.so +0 -0
- data/lib/extension_helper.rb +28 -0
- metadata +163 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
if RUBY_PLATFORM == 'java'
|
2
|
+
|
3
|
+
require 'concurrent/executor/java_thread_pool_executor'
|
4
|
+
|
5
|
+
module Concurrent
|
6
|
+
|
7
|
+
# @!macro cached_thread_pool
|
8
|
+
class JavaCachedThreadPool < JavaThreadPoolExecutor
|
9
|
+
|
10
|
+
# Create a new thread pool.
|
11
|
+
#
|
12
|
+
# @param [Hash] opts the options defining pool behavior.
|
13
|
+
# @option opts [Symbol] :overflow_policy (`:abort`) the overflow policy
|
14
|
+
#
|
15
|
+
# @raise [ArgumentError] if `overflow_policy` is not a known policy
|
16
|
+
#
|
17
|
+
# @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newCachedThreadPool--
|
18
|
+
def initialize(opts = {})
|
19
|
+
@overflow_policy = opts.fetch(:overflow_policy, :abort)
|
20
|
+
@max_queue = 0
|
21
|
+
|
22
|
+
raise ArgumentError.new("#{@overflow_policy} is not a valid overflow policy") unless OVERFLOW_POLICIES.keys.include?(@overflow_policy)
|
23
|
+
|
24
|
+
@executor = java.util.concurrent.Executors.newCachedThreadPool
|
25
|
+
@executor.setRejectedExecutionHandler(OVERFLOW_POLICIES[@overflow_policy].new)
|
26
|
+
|
27
|
+
set_shutdown_hook
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
if RUBY_PLATFORM == 'java'
|
2
|
+
|
3
|
+
require 'concurrent/executor/java_thread_pool_executor'
|
4
|
+
|
5
|
+
module Concurrent
|
6
|
+
|
7
|
+
# @!macro fixed_thread_pool
|
8
|
+
class JavaFixedThreadPool < JavaThreadPoolExecutor
|
9
|
+
|
10
|
+
# Create a new thread pool.
|
11
|
+
#
|
12
|
+
# @param [Hash] opts the options defining pool behavior.
|
13
|
+
# @option opts [Symbol] :overflow_policy (`:abort`) the overflow policy
|
14
|
+
#
|
15
|
+
# @raise [ArgumentError] if `num_threads` is less than or equal to zero
|
16
|
+
# @raise [ArgumentError] if `overflow_policy` is not a known policy
|
17
|
+
#
|
18
|
+
# @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newFixedThreadPool-int-
|
19
|
+
def initialize(num_threads, opts = {})
|
20
|
+
|
21
|
+
opts = {
|
22
|
+
min_threads: num_threads,
|
23
|
+
max_threads: num_threads
|
24
|
+
}.merge(opts)
|
25
|
+
super(opts)
|
26
|
+
|
27
|
+
|
28
|
+
#@overflow_policy = opts.fetch(:overflow_policy, :abort)
|
29
|
+
#@max_queue = 0
|
30
|
+
#
|
31
|
+
#raise ArgumentError.new('number of threads must be greater than zero') if num_threads < 1
|
32
|
+
#raise ArgumentError.new("#{@overflow_policy} is not a valid overflow policy") unless OVERFLOW_POLICIES.keys.include?(@overflow_policy)
|
33
|
+
#
|
34
|
+
#@executor = java.util.concurrent.Executors.newFixedThreadPool(num_threads)
|
35
|
+
#@executor.setRejectedExecutionHandler(OVERFLOW_POLICIES[@overflow_policy].new)
|
36
|
+
|
37
|
+
set_shutdown_hook
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
if RUBY_PLATFORM == 'java'
|
2
|
+
require_relative 'executor'
|
3
|
+
|
4
|
+
module Concurrent
|
5
|
+
|
6
|
+
# @!macro single_thread_executor
|
7
|
+
class JavaSingleThreadExecutor
|
8
|
+
include JavaExecutor
|
9
|
+
include SerialExecutor
|
10
|
+
|
11
|
+
# Create a new thread pool.
|
12
|
+
#
|
13
|
+
# @see http://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html
|
14
|
+
# @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html
|
15
|
+
# @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html
|
16
|
+
def initialize(opts = {})
|
17
|
+
@executor = java.util.concurrent.Executors.newSingleThreadExecutor
|
18
|
+
set_shutdown_hook
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
if RUBY_PLATFORM == 'java'
|
2
|
+
require_relative 'executor'
|
3
|
+
|
4
|
+
module Concurrent
|
5
|
+
|
6
|
+
# @!macro thread_pool_executor
|
7
|
+
class JavaThreadPoolExecutor
|
8
|
+
include JavaExecutor
|
9
|
+
|
10
|
+
# Default maximum number of threads that will be created in the pool.
|
11
|
+
DEFAULT_MAX_POOL_SIZE = java.lang.Integer::MAX_VALUE # 2147483647
|
12
|
+
|
13
|
+
# Default minimum number of threads that will be retained in the pool.
|
14
|
+
DEFAULT_MIN_POOL_SIZE = 0
|
15
|
+
|
16
|
+
# Default maximum number of tasks that may be added to the task queue.
|
17
|
+
DEFAULT_MAX_QUEUE_SIZE = 0
|
18
|
+
|
19
|
+
# Default maximum number of seconds a thread in the pool may remain idle
|
20
|
+
# before being reclaimed.
|
21
|
+
DEFAULT_THREAD_IDLETIMEOUT = 60
|
22
|
+
|
23
|
+
# The set of possible overflow policies that may be set at thread pool creation.
|
24
|
+
OVERFLOW_POLICIES = {
|
25
|
+
abort: java.util.concurrent.ThreadPoolExecutor::AbortPolicy,
|
26
|
+
discard: java.util.concurrent.ThreadPoolExecutor::DiscardPolicy,
|
27
|
+
caller_runs: java.util.concurrent.ThreadPoolExecutor::CallerRunsPolicy
|
28
|
+
}.freeze
|
29
|
+
|
30
|
+
# The maximum number of threads that may be created in the pool.
|
31
|
+
attr_reader :max_length
|
32
|
+
|
33
|
+
# The maximum number of tasks that may be waiting in the work queue at any one time.
|
34
|
+
# When the queue size reaches `max_queue` subsequent tasks will be rejected in
|
35
|
+
# accordance with the configured `overflow_policy`.
|
36
|
+
attr_reader :max_queue
|
37
|
+
|
38
|
+
# The policy defining how rejected tasks (tasks received once the queue size reaches
|
39
|
+
# the configured `max_queue`) are handled. Must be one of the values specified in
|
40
|
+
# `OVERFLOW_POLICIES`.
|
41
|
+
attr_reader :overflow_policy
|
42
|
+
|
43
|
+
# Create a new thread pool.
|
44
|
+
#
|
45
|
+
# @param [Hash] opts the options which configure the thread pool
|
46
|
+
#
|
47
|
+
# @option opts [Integer] :max_threads (DEFAULT_MAX_POOL_SIZE) the maximum
|
48
|
+
# number of threads to be created
|
49
|
+
# @option opts [Integer] :min_threads (DEFAULT_MIN_POOL_SIZE) the minimum
|
50
|
+
# number of threads to be retained
|
51
|
+
# @option opts [Integer] :idletime (DEFAULT_THREAD_IDLETIMEOUT) the maximum
|
52
|
+
# number of seconds a thread may be idle before being reclaimed
|
53
|
+
# @option opts [Integer] :max_queue (DEFAULT_MAX_QUEUE_SIZE) the maximum
|
54
|
+
# number of tasks allowed in the work queue at any one time; a value of
|
55
|
+
# zero means the queue may grow without bounnd
|
56
|
+
# @option opts [Symbol] :overflow_policy (:abort) the policy for handling new
|
57
|
+
# tasks that are received when the queue size has reached `max_queue`
|
58
|
+
#
|
59
|
+
# @raise [ArgumentError] if `:max_threads` is less than one
|
60
|
+
# @raise [ArgumentError] if `:min_threads` is less than zero
|
61
|
+
# @raise [ArgumentError] if `:overflow_policy` is not one of the values specified
|
62
|
+
# in `OVERFLOW_POLICIES`
|
63
|
+
#
|
64
|
+
# @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html
|
65
|
+
def initialize(opts = {})
|
66
|
+
min_length = opts.fetch(:min_threads, DEFAULT_MIN_POOL_SIZE).to_i
|
67
|
+
max_length = opts.fetch(:max_threads, DEFAULT_MAX_POOL_SIZE).to_i
|
68
|
+
idletime = opts.fetch(:idletime, DEFAULT_THREAD_IDLETIMEOUT).to_i
|
69
|
+
@max_queue = opts.fetch(:max_queue, DEFAULT_MAX_QUEUE_SIZE).to_i
|
70
|
+
@overflow_policy = opts.fetch(:overflow_policy, :abort)
|
71
|
+
|
72
|
+
raise ArgumentError.new('max_threads must be greater than zero') if max_length <= 0
|
73
|
+
raise ArgumentError.new('min_threads cannot be less than zero') if min_length < 0
|
74
|
+
raise ArgumentError.new('min_threads cannot be more than max_threads') if min_length > max_length
|
75
|
+
raise ArgumentError.new("#{@overflow_policy} is not a valid overflow policy") unless OVERFLOW_POLICIES.keys.include?(@overflow_policy)
|
76
|
+
|
77
|
+
if min_length == 0 && @max_queue == 0
|
78
|
+
queue = java.util.concurrent.SynchronousQueue.new
|
79
|
+
elsif @max_queue == 0
|
80
|
+
queue = java.util.concurrent.LinkedBlockingQueue.new
|
81
|
+
else
|
82
|
+
queue = java.util.concurrent.LinkedBlockingQueue.new(@max_queue)
|
83
|
+
end
|
84
|
+
|
85
|
+
@executor = java.util.concurrent.ThreadPoolExecutor.new(
|
86
|
+
min_length, max_length,
|
87
|
+
idletime, java.util.concurrent.TimeUnit::SECONDS,
|
88
|
+
queue, OVERFLOW_POLICIES[@overflow_policy].new)
|
89
|
+
|
90
|
+
set_shutdown_hook
|
91
|
+
end
|
92
|
+
|
93
|
+
# @!macro executor_module_method_can_overflow_question
|
94
|
+
def can_overflow?
|
95
|
+
@max_queue != 0
|
96
|
+
end
|
97
|
+
|
98
|
+
# The minimum number of threads that may be retained in the pool.
|
99
|
+
#
|
100
|
+
# @return [Integer] the min_length
|
101
|
+
def min_length
|
102
|
+
@executor.getCorePoolSize
|
103
|
+
end
|
104
|
+
|
105
|
+
# The maximum number of threads that may be created in the pool.
|
106
|
+
#
|
107
|
+
# @return [Integer] the max_length
|
108
|
+
def max_length
|
109
|
+
@executor.getMaximumPoolSize
|
110
|
+
end
|
111
|
+
|
112
|
+
# The number of threads currently in the pool.
|
113
|
+
#
|
114
|
+
# @return [Integer] the length
|
115
|
+
def length
|
116
|
+
@executor.getPoolSize
|
117
|
+
end
|
118
|
+
alias_method :current_length, :length
|
119
|
+
|
120
|
+
# The largest number of threads that have been created in the pool since construction.
|
121
|
+
#
|
122
|
+
# @return [Integer] the largest_length
|
123
|
+
def largest_length
|
124
|
+
@executor.getLargestPoolSize
|
125
|
+
end
|
126
|
+
|
127
|
+
# The number of tasks that have been scheduled for execution on the pool since construction.
|
128
|
+
#
|
129
|
+
# @return [Integer] the scheduled_task_count
|
130
|
+
def scheduled_task_count
|
131
|
+
@executor.getTaskCount
|
132
|
+
end
|
133
|
+
|
134
|
+
# The number of tasks that have been completed by the pool since construction.
|
135
|
+
#
|
136
|
+
# @return [Integer] the completed_task_count
|
137
|
+
def completed_task_count
|
138
|
+
@executor.getCompletedTaskCount
|
139
|
+
end
|
140
|
+
|
141
|
+
# The number of seconds that a thread may be idle before being reclaimed.
|
142
|
+
#
|
143
|
+
# @return [Integer] the idletime
|
144
|
+
def idletime
|
145
|
+
@executor.getKeepAliveTime(java.util.concurrent.TimeUnit::SECONDS)
|
146
|
+
end
|
147
|
+
|
148
|
+
# The number of tasks in the queue awaiting execution.
|
149
|
+
#
|
150
|
+
# @return [Integer] the queue_length
|
151
|
+
def queue_length
|
152
|
+
@executor.getQueue.size
|
153
|
+
end
|
154
|
+
|
155
|
+
# Number of tasks that may be enqueued before reaching `max_queue` and rejecting
|
156
|
+
# new tasks. A value of -1 indicates that the queue may grow without bound.
|
157
|
+
#
|
158
|
+
# @return [Integer] the remaining_capacity
|
159
|
+
def remaining_capacity
|
160
|
+
@max_queue == 0 ? -1 : @executor.getQueue.remainingCapacity
|
161
|
+
end
|
162
|
+
|
163
|
+
# This method is deprecated and will be removed soon.
|
164
|
+
# This method is supost to return the threads status, but Java API doesn't
|
165
|
+
# provide a way to get the thread status. So we return an empty Array instead.
|
166
|
+
def status
|
167
|
+
warn '[DEPRECATED] `status` is deprecated and will be removed soon.'
|
168
|
+
warn "Calls to `status` return an empty Array. Java ThreadPoolExecutor does not provide thread's status."
|
169
|
+
[]
|
170
|
+
end
|
171
|
+
|
172
|
+
# Is the thread pool running?
|
173
|
+
#
|
174
|
+
# @return [Boolean] `true` when running, `false` when shutting down or shutdown
|
175
|
+
def running?
|
176
|
+
super && !@executor.isTerminating
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'concurrent/atomics'
|
2
|
+
require 'concurrent/executor/executor'
|
3
|
+
|
4
|
+
module Concurrent
|
5
|
+
|
6
|
+
# An executor service in which every operation spawns a new,
|
7
|
+
# independently operating thread.
|
8
|
+
#
|
9
|
+
# This is perhaps the most inefficient executor service in this
|
10
|
+
# library. It exists mainly for testing an debugging. Thread creation
|
11
|
+
# and management is expensive in Ruby and this executor performs no
|
12
|
+
# resource pooling. This can be very beneficial during testing and
|
13
|
+
# debugging because it decouples the using code from the underlying
|
14
|
+
# executor implementation. In production this executor will likely
|
15
|
+
# lead to suboptimal performance.
|
16
|
+
#
|
17
|
+
# @note Intended for use primarily in testing and debugging.
|
18
|
+
class PerThreadExecutor
|
19
|
+
include Executor
|
20
|
+
|
21
|
+
# Creates a new executor
|
22
|
+
def initialize
|
23
|
+
@running = Concurrent::AtomicBoolean.new(true)
|
24
|
+
@stopped = Concurrent::Event.new
|
25
|
+
@count = Concurrent::AtomicFixnum.new(0)
|
26
|
+
end
|
27
|
+
|
28
|
+
# @!macro executor_method_post
|
29
|
+
def self.post(*args)
|
30
|
+
raise ArgumentError.new('no block given') unless block_given?
|
31
|
+
Thread.new(*args) do
|
32
|
+
Thread.current.abort_on_exception = false
|
33
|
+
yield(*args)
|
34
|
+
end
|
35
|
+
true
|
36
|
+
end
|
37
|
+
|
38
|
+
# @!macro executor_method_left_shift
|
39
|
+
def self.<<(task)
|
40
|
+
post(&task)
|
41
|
+
self
|
42
|
+
end
|
43
|
+
|
44
|
+
# @!macro executor_method_post
|
45
|
+
def post(*args, &task)
|
46
|
+
raise ArgumentError.new('no block given') unless block_given?
|
47
|
+
return false unless running?
|
48
|
+
@count.increment
|
49
|
+
Thread.new(*args) do
|
50
|
+
Thread.current.abort_on_exception = false
|
51
|
+
begin
|
52
|
+
yield(*args)
|
53
|
+
ensure
|
54
|
+
@count.decrement
|
55
|
+
@stopped.set if @running.false? && @count.value == 0
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# @!macro executor_method_left_shift
|
61
|
+
def <<(task)
|
62
|
+
post(&task)
|
63
|
+
self
|
64
|
+
end
|
65
|
+
|
66
|
+
# @!macro executor_method_running_question
|
67
|
+
def running?
|
68
|
+
@running.true?
|
69
|
+
end
|
70
|
+
|
71
|
+
# @!macro executor_method_shuttingdown_question
|
72
|
+
def shuttingdown?
|
73
|
+
@running.false? && ! @stopped.set?
|
74
|
+
end
|
75
|
+
|
76
|
+
# @!macro executor_method_shutdown_question
|
77
|
+
def shutdown?
|
78
|
+
@stopped.set?
|
79
|
+
end
|
80
|
+
|
81
|
+
# @!macro executor_method_shutdown
|
82
|
+
def shutdown
|
83
|
+
@running.make_false
|
84
|
+
@stopped.set if @count.value == 0
|
85
|
+
true
|
86
|
+
end
|
87
|
+
|
88
|
+
# @!macro executor_method_kill
|
89
|
+
def kill
|
90
|
+
@running.make_false
|
91
|
+
@stopped.set
|
92
|
+
true
|
93
|
+
end
|
94
|
+
|
95
|
+
# @!macro executor_method_wait_for_termination
|
96
|
+
def wait_for_termination(timeout = nil)
|
97
|
+
@stopped.wait(timeout)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'concurrent/executor/ruby_thread_pool_executor'
|
2
|
+
|
3
|
+
module Concurrent
|
4
|
+
|
5
|
+
# @!macro cached_thread_pool
|
6
|
+
class RubyCachedThreadPool < RubyThreadPoolExecutor
|
7
|
+
|
8
|
+
# Create a new thread pool.
|
9
|
+
#
|
10
|
+
# @param [Hash] opts the options defining pool behavior.
|
11
|
+
# number of seconds a thread may be idle before it is reclaimed
|
12
|
+
#
|
13
|
+
# @raise [ArgumentError] if `overflow_policy` is not a known policy
|
14
|
+
def initialize(opts = {})
|
15
|
+
overflow_policy = opts.fetch(:overflow_policy, :abort)
|
16
|
+
|
17
|
+
raise ArgumentError.new("#{overflow_policy} is not a valid overflow policy") unless OVERFLOW_POLICIES.include?(overflow_policy)
|
18
|
+
|
19
|
+
opts = opts.merge(
|
20
|
+
min_threads: 0,
|
21
|
+
max_threads: DEFAULT_MAX_POOL_SIZE,
|
22
|
+
overflow_policy: overflow_policy,
|
23
|
+
max_queue: DEFAULT_MAX_QUEUE_SIZE,
|
24
|
+
idletime: DEFAULT_THREAD_IDLETIMEOUT
|
25
|
+
)
|
26
|
+
super(opts)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'concurrent/executor/ruby_thread_pool_executor'
|
2
|
+
|
3
|
+
module Concurrent
|
4
|
+
|
5
|
+
# @!macro fixed_thread_pool
|
6
|
+
class RubyFixedThreadPool < RubyThreadPoolExecutor
|
7
|
+
|
8
|
+
# Create a new thread pool.
|
9
|
+
#
|
10
|
+
# @param [Integer] num_threads the number of threads to allocate
|
11
|
+
# @param [Hash] opts the options defining pool behavior.
|
12
|
+
# @option opts [Symbol] :overflow_policy (`:abort`) the overflow policy
|
13
|
+
#
|
14
|
+
# @raise [ArgumentError] if `num_threads` is less than or equal to zero
|
15
|
+
# @raise [ArgumentError] if `overflow_policy` is not a known policy
|
16
|
+
def initialize(num_threads, opts = {})
|
17
|
+
overflow_policy = opts.fetch(:overflow_policy, :abort)
|
18
|
+
|
19
|
+
raise ArgumentError.new('number of threads must be greater than zero') if num_threads < 1
|
20
|
+
raise ArgumentError.new("#{overflow_policy} is not a valid overflow policy") unless OVERFLOW_POLICIES.include?(overflow_policy)
|
21
|
+
|
22
|
+
opts = {
|
23
|
+
min_threads: num_threads,
|
24
|
+
max_threads: num_threads,
|
25
|
+
overflow_policy: overflow_policy,
|
26
|
+
max_queue: DEFAULT_MAX_QUEUE_SIZE,
|
27
|
+
idletime: DEFAULT_THREAD_IDLETIMEOUT,
|
28
|
+
}.merge(opts)
|
29
|
+
super(opts)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require_relative 'executor'
|
2
|
+
|
3
|
+
module Concurrent
|
4
|
+
|
5
|
+
# @!macro single_thread_executor
|
6
|
+
class RubySingleThreadExecutor
|
7
|
+
include RubyExecutor
|
8
|
+
include SerialExecutor
|
9
|
+
|
10
|
+
# Create a new thread pool.
|
11
|
+
#
|
12
|
+
# @see http://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html
|
13
|
+
# @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html
|
14
|
+
# @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html
|
15
|
+
def initialize(opts = {})
|
16
|
+
@queue = Queue.new
|
17
|
+
@thread = nil
|
18
|
+
init_executor
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
# @!visibility private
|
24
|
+
def execute(*args, &task)
|
25
|
+
supervise
|
26
|
+
@queue << [args, task]
|
27
|
+
end
|
28
|
+
|
29
|
+
# @!visibility private
|
30
|
+
def shutdown_execution
|
31
|
+
@queue << :stop
|
32
|
+
stopped_event.set unless alive?
|
33
|
+
end
|
34
|
+
|
35
|
+
# @!visibility private
|
36
|
+
def kill_execution
|
37
|
+
@queue.clear
|
38
|
+
@thread.kill if alive?
|
39
|
+
end
|
40
|
+
|
41
|
+
# @!visibility private
|
42
|
+
def alive?
|
43
|
+
@thread && @thread.alive?
|
44
|
+
end
|
45
|
+
|
46
|
+
# @!visibility private
|
47
|
+
def supervise
|
48
|
+
@thread = new_worker_thread unless alive?
|
49
|
+
end
|
50
|
+
|
51
|
+
# @!visibility private
|
52
|
+
def new_worker_thread
|
53
|
+
Thread.new do
|
54
|
+
Thread.current.abort_on_exception = false
|
55
|
+
work
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# @!visibility private
|
60
|
+
def work
|
61
|
+
loop do
|
62
|
+
task = @queue.pop
|
63
|
+
break if task == :stop
|
64
|
+
begin
|
65
|
+
task.last.call(*task.first)
|
66
|
+
rescue => ex
|
67
|
+
# let it fail
|
68
|
+
log DEBUG, ex
|
69
|
+
end
|
70
|
+
end
|
71
|
+
stopped_event.set
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|