concurrent-ruby 0.8.0 → 0.9.0.pre2
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 +97 -2
- data/README.md +103 -54
- data/lib/concurrent.rb +34 -14
- data/lib/concurrent/async.rb +164 -50
- data/lib/concurrent/atom.rb +171 -0
- data/lib/concurrent/atomic/atomic_boolean.rb +57 -107
- data/lib/concurrent/atomic/atomic_fixnum.rb +73 -101
- data/lib/concurrent/atomic/atomic_reference.rb +49 -0
- data/lib/concurrent/atomic/condition.rb +23 -12
- data/lib/concurrent/atomic/count_down_latch.rb +23 -21
- data/lib/concurrent/atomic/cyclic_barrier.rb +47 -47
- data/lib/concurrent/atomic/event.rb +33 -42
- data/lib/concurrent/atomic/read_write_lock.rb +252 -0
- data/lib/concurrent/atomic/semaphore.rb +64 -89
- data/lib/concurrent/atomic/thread_local_var.rb +130 -58
- data/lib/concurrent/atomic/thread_local_var/weak_key_map.rb +236 -0
- data/lib/concurrent/atomic_reference/direct_update.rb +3 -0
- data/lib/concurrent/atomic_reference/jruby.rb +6 -3
- data/lib/concurrent/atomic_reference/mutex_atomic.rb +10 -32
- data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +3 -0
- data/lib/concurrent/atomic_reference/rbx.rb +4 -1
- data/lib/concurrent/atomic_reference/ruby.rb +6 -3
- data/lib/concurrent/atomics.rb +74 -4
- data/lib/concurrent/collection/copy_on_notify_observer_set.rb +115 -0
- data/lib/concurrent/collection/copy_on_write_observer_set.rb +119 -0
- data/lib/concurrent/collection/priority_queue.rb +300 -245
- data/lib/concurrent/concern/deprecation.rb +27 -0
- data/lib/concurrent/concern/dereferenceable.rb +88 -0
- data/lib/concurrent/concern/logging.rb +25 -0
- data/lib/concurrent/concern/obligation.rb +228 -0
- data/lib/concurrent/concern/observable.rb +85 -0
- data/lib/concurrent/configuration.rb +226 -112
- data/lib/concurrent/dataflow.rb +2 -3
- data/lib/concurrent/delay.rb +141 -50
- data/lib/concurrent/edge.rb +30 -0
- data/lib/concurrent/errors.rb +10 -0
- data/lib/concurrent/exchanger.rb +25 -1
- data/lib/concurrent/executor/cached_thread_pool.rb +46 -33
- data/lib/concurrent/executor/executor.rb +46 -299
- data/lib/concurrent/executor/executor_service.rb +521 -0
- data/lib/concurrent/executor/fixed_thread_pool.rb +206 -26
- data/lib/concurrent/executor/immediate_executor.rb +9 -9
- data/lib/concurrent/executor/indirect_immediate_executor.rb +4 -3
- data/lib/concurrent/executor/java_cached_thread_pool.rb +18 -16
- data/lib/concurrent/executor/java_fixed_thread_pool.rb +11 -18
- data/lib/concurrent/executor/java_single_thread_executor.rb +17 -16
- data/lib/concurrent/executor/java_thread_pool_executor.rb +55 -102
- data/lib/concurrent/executor/ruby_cached_thread_pool.rb +9 -18
- data/lib/concurrent/executor/ruby_fixed_thread_pool.rb +10 -21
- data/lib/concurrent/executor/ruby_single_thread_executor.rb +14 -16
- data/lib/concurrent/executor/ruby_thread_pool_executor.rb +250 -166
- data/lib/concurrent/executor/safe_task_executor.rb +5 -4
- data/lib/concurrent/executor/serialized_execution.rb +22 -18
- data/lib/concurrent/executor/{per_thread_executor.rb → simple_executor_service.rb} +29 -20
- data/lib/concurrent/executor/single_thread_executor.rb +32 -21
- data/lib/concurrent/executor/thread_pool_executor.rb +72 -60
- data/lib/concurrent/executor/timer_set.rb +96 -84
- data/lib/concurrent/executors.rb +1 -1
- data/lib/concurrent/future.rb +70 -38
- data/lib/concurrent/immutable_struct.rb +89 -0
- data/lib/concurrent/ivar.rb +152 -60
- data/lib/concurrent/lazy_register.rb +40 -20
- data/lib/concurrent/maybe.rb +226 -0
- data/lib/concurrent/mutable_struct.rb +227 -0
- data/lib/concurrent/mvar.rb +44 -43
- data/lib/concurrent/promise.rb +208 -134
- data/lib/concurrent/scheduled_task.rb +339 -43
- data/lib/concurrent/settable_struct.rb +127 -0
- data/lib/concurrent/synchronization.rb +17 -0
- data/lib/concurrent/synchronization/abstract_object.rb +163 -0
- data/lib/concurrent/synchronization/abstract_struct.rb +158 -0
- data/lib/concurrent/synchronization/condition.rb +53 -0
- data/lib/concurrent/synchronization/java_object.rb +35 -0
- data/lib/concurrent/synchronization/lock.rb +32 -0
- data/lib/concurrent/synchronization/monitor_object.rb +24 -0
- data/lib/concurrent/synchronization/mutex_object.rb +43 -0
- data/lib/concurrent/synchronization/object.rb +78 -0
- data/lib/concurrent/synchronization/rbx_object.rb +75 -0
- data/lib/concurrent/timer_task.rb +87 -100
- data/lib/concurrent/tvar.rb +42 -38
- data/lib/concurrent/utilities.rb +3 -1
- data/lib/concurrent/utility/at_exit.rb +97 -0
- data/lib/concurrent/utility/engine.rb +40 -0
- data/lib/concurrent/utility/monotonic_time.rb +59 -0
- data/lib/concurrent/utility/native_extension_loader.rb +56 -0
- data/lib/concurrent/utility/processor_counter.rb +156 -0
- data/lib/concurrent/utility/timeout.rb +18 -14
- data/lib/concurrent/utility/timer.rb +11 -6
- data/lib/concurrent/version.rb +2 -1
- data/lib/concurrent_ruby.rb +1 -0
- metadata +47 -83
- data/lib/concurrent/actor.rb +0 -103
- data/lib/concurrent/actor/behaviour.rb +0 -70
- data/lib/concurrent/actor/behaviour/abstract.rb +0 -48
- data/lib/concurrent/actor/behaviour/awaits.rb +0 -21
- data/lib/concurrent/actor/behaviour/buffer.rb +0 -54
- data/lib/concurrent/actor/behaviour/errors_on_unknown_message.rb +0 -12
- data/lib/concurrent/actor/behaviour/executes_context.rb +0 -18
- data/lib/concurrent/actor/behaviour/linking.rb +0 -45
- data/lib/concurrent/actor/behaviour/pausing.rb +0 -77
- data/lib/concurrent/actor/behaviour/removes_child.rb +0 -16
- data/lib/concurrent/actor/behaviour/sets_results.rb +0 -36
- data/lib/concurrent/actor/behaviour/supervised.rb +0 -59
- data/lib/concurrent/actor/behaviour/supervising.rb +0 -34
- data/lib/concurrent/actor/behaviour/terminates_children.rb +0 -13
- data/lib/concurrent/actor/behaviour/termination.rb +0 -54
- data/lib/concurrent/actor/context.rb +0 -154
- data/lib/concurrent/actor/core.rb +0 -217
- data/lib/concurrent/actor/default_dead_letter_handler.rb +0 -9
- data/lib/concurrent/actor/envelope.rb +0 -41
- data/lib/concurrent/actor/errors.rb +0 -27
- data/lib/concurrent/actor/internal_delegations.rb +0 -49
- data/lib/concurrent/actor/public_delegations.rb +0 -40
- data/lib/concurrent/actor/reference.rb +0 -81
- data/lib/concurrent/actor/root.rb +0 -37
- data/lib/concurrent/actor/type_check.rb +0 -48
- data/lib/concurrent/actor/utils.rb +0 -10
- data/lib/concurrent/actor/utils/ad_hoc.rb +0 -21
- data/lib/concurrent/actor/utils/balancer.rb +0 -42
- data/lib/concurrent/actor/utils/broadcast.rb +0 -52
- data/lib/concurrent/actor/utils/pool.rb +0 -59
- data/lib/concurrent/actress.rb +0 -3
- data/lib/concurrent/agent.rb +0 -209
- data/lib/concurrent/atomic.rb +0 -92
- data/lib/concurrent/atomic/copy_on_notify_observer_set.rb +0 -118
- data/lib/concurrent/atomic/copy_on_write_observer_set.rb +0 -117
- data/lib/concurrent/atomic/synchronization.rb +0 -51
- data/lib/concurrent/channel/buffered_channel.rb +0 -85
- data/lib/concurrent/channel/channel.rb +0 -41
- data/lib/concurrent/channel/unbuffered_channel.rb +0 -35
- data/lib/concurrent/channel/waitable_list.rb +0 -40
- data/lib/concurrent/channels.rb +0 -5
- data/lib/concurrent/collection/blocking_ring_buffer.rb +0 -71
- data/lib/concurrent/collection/ring_buffer.rb +0 -59
- data/lib/concurrent/collections.rb +0 -3
- data/lib/concurrent/dereferenceable.rb +0 -108
- data/lib/concurrent/executor/ruby_thread_pool_worker.rb +0 -73
- data/lib/concurrent/logging.rb +0 -20
- data/lib/concurrent/obligation.rb +0 -171
- data/lib/concurrent/observable.rb +0 -73
- data/lib/concurrent/options_parser.rb +0 -52
- data/lib/concurrent/utility/processor_count.rb +0 -152
- data/lib/extension_helper.rb +0 -37
@@ -0,0 +1,521 @@
|
|
1
|
+
require 'concurrent/errors'
|
2
|
+
require 'concurrent/concern/deprecation'
|
3
|
+
require 'concurrent/concern/logging'
|
4
|
+
require 'concurrent/atomic/event'
|
5
|
+
require 'concurrent/synchronization'
|
6
|
+
require 'concurrent/utility/at_exit'
|
7
|
+
|
8
|
+
module Concurrent
|
9
|
+
|
10
|
+
# @!macro [new] executor_service_method_post
|
11
|
+
#
|
12
|
+
# Submit a task to the executor for asynchronous processing.
|
13
|
+
#
|
14
|
+
# @param [Array] args zero or more arguments to be passed to the task
|
15
|
+
#
|
16
|
+
# @yield the asynchronous task to perform
|
17
|
+
#
|
18
|
+
# @return [Boolean] `true` if the task is queued, `false` if the executor
|
19
|
+
# is not running
|
20
|
+
#
|
21
|
+
# @raise [ArgumentError] if no task is given
|
22
|
+
|
23
|
+
# @!macro [new] executor_service_method_left_shift
|
24
|
+
#
|
25
|
+
# Submit a task to the executor for asynchronous processing.
|
26
|
+
#
|
27
|
+
# @param [Proc] task the asynchronous task to perform
|
28
|
+
#
|
29
|
+
# @return [self] returns itself
|
30
|
+
|
31
|
+
# @!macro [new] executor_service_method_can_overflow_question
|
32
|
+
#
|
33
|
+
# Does the task queue have a maximum size?
|
34
|
+
#
|
35
|
+
# @return [Boolean] True if the task queue has a maximum size else false.
|
36
|
+
|
37
|
+
# @!macro [new] executor_service_method_serialized_question
|
38
|
+
#
|
39
|
+
# Does this executor guarantee serialization of its operations?
|
40
|
+
#
|
41
|
+
# @return [Boolean] True if the executor guarantees that all operations
|
42
|
+
# will be post in the order they are received and no two operations may
|
43
|
+
# occur simultaneously. Else false.
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
# @!macro [new] executor_service_public_api
|
50
|
+
#
|
51
|
+
# @!method post(*args, &task)
|
52
|
+
# @!macro executor_service_method_post
|
53
|
+
#
|
54
|
+
# @!method <<(task)
|
55
|
+
# @!macro executor_service_method_left_shift
|
56
|
+
#
|
57
|
+
# @!method can_overflow?
|
58
|
+
# @!macro executor_service_method_can_overflow_question
|
59
|
+
#
|
60
|
+
# @!method serialized?
|
61
|
+
# @!macro executor_service_method_serialized_question
|
62
|
+
|
63
|
+
|
64
|
+
|
65
|
+
|
66
|
+
|
67
|
+
# @!macro executor_service_public_api
|
68
|
+
# @!visibility private
|
69
|
+
module ExecutorService
|
70
|
+
include Concern::Logging
|
71
|
+
include Concern::Deprecation
|
72
|
+
|
73
|
+
# @!macro executor_service_method_post
|
74
|
+
def post(*args, &task)
|
75
|
+
raise NotImplementedError
|
76
|
+
end
|
77
|
+
|
78
|
+
# @!macro executor_service_method_left_shift
|
79
|
+
def <<(task)
|
80
|
+
post(&task)
|
81
|
+
self
|
82
|
+
end
|
83
|
+
|
84
|
+
# @!macro executor_service_method_can_overflow_question
|
85
|
+
#
|
86
|
+
# @note Always returns `false`
|
87
|
+
def can_overflow?
|
88
|
+
false
|
89
|
+
end
|
90
|
+
|
91
|
+
# @!macro executor_service_method_serialized_question
|
92
|
+
#
|
93
|
+
# @note Always returns `false`
|
94
|
+
def serialized?
|
95
|
+
false
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Indicates that the including `ExecutorService` guarantees
|
100
|
+
# that all operations will occur in the order they are post and that no
|
101
|
+
# two operations may occur simultaneously. This module provides no
|
102
|
+
# functionality and provides no guarantees. That is the responsibility
|
103
|
+
# of the including class. This module exists solely to allow the including
|
104
|
+
# object to be interrogated for its serialization status.
|
105
|
+
#
|
106
|
+
# @example
|
107
|
+
# class Foo
|
108
|
+
# include Concurrent::SerialExecutor
|
109
|
+
# end
|
110
|
+
#
|
111
|
+
# foo = Foo.new
|
112
|
+
#
|
113
|
+
# foo.is_a? Concurrent::ExecutorService #=> true
|
114
|
+
# foo.is_a? Concurrent::SerialExecutor #=> true
|
115
|
+
# foo.serialized? #=> true
|
116
|
+
#
|
117
|
+
# @!visibility private
|
118
|
+
module SerialExecutorService
|
119
|
+
include ExecutorService
|
120
|
+
|
121
|
+
# @!macro executor_service_method_serialized_question
|
122
|
+
#
|
123
|
+
# @note Always returns `true`
|
124
|
+
def serialized?
|
125
|
+
true
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
|
131
|
+
|
132
|
+
|
133
|
+
# @!macro [new] executor_service_attr_reader_fallback_policy
|
134
|
+
# @return [Symbol] The fallback policy in effect. Either `:abort`, `:discard`, or `:caller_runs`.
|
135
|
+
|
136
|
+
# @!macro [new] executor_service_method_shutdown
|
137
|
+
#
|
138
|
+
# Begin an orderly shutdown. Tasks already in the queue will be executed,
|
139
|
+
# but no new tasks will be accepted. Has no additional effect if the
|
140
|
+
# thread pool is not running.
|
141
|
+
|
142
|
+
# @!macro [new] executor_service_method_kill
|
143
|
+
#
|
144
|
+
# Begin an immediate shutdown. In-progress tasks will be allowed to
|
145
|
+
# complete but enqueued tasks will be dismissed and no new tasks
|
146
|
+
# will be accepted. Has no additional effect if the thread pool is
|
147
|
+
# not running.
|
148
|
+
|
149
|
+
# @!macro [new] executor_service_method_wait_for_termination
|
150
|
+
#
|
151
|
+
# Block until executor shutdown is complete or until `timeout` seconds have
|
152
|
+
# passed.
|
153
|
+
#
|
154
|
+
# @note Does not initiate shutdown or termination. Either `shutdown` or `kill`
|
155
|
+
# must be called before this method (or on another thread).
|
156
|
+
#
|
157
|
+
# @param [Integer] timeout the maximum number of seconds to wait for shutdown to complete
|
158
|
+
#
|
159
|
+
# @return [Boolean] `true` if shutdown complete or false on `timeout`
|
160
|
+
|
161
|
+
# @!macro [new] executor_service_method_running_question
|
162
|
+
#
|
163
|
+
# Is the executor running?
|
164
|
+
#
|
165
|
+
# @return [Boolean] `true` when running, `false` when shutting down or shutdown
|
166
|
+
|
167
|
+
# @!macro [new] executor_service_method_shuttingdown_question
|
168
|
+
#
|
169
|
+
# Is the executor shuttingdown?
|
170
|
+
#
|
171
|
+
# @return [Boolean] `true` when not running and not shutdown, else `false`
|
172
|
+
|
173
|
+
# @!macro [new] executor_service_method_shutdown_question
|
174
|
+
#
|
175
|
+
# Is the executor shutdown?
|
176
|
+
#
|
177
|
+
# @return [Boolean] `true` when shutdown, `false` when shutting down or running
|
178
|
+
|
179
|
+
# @!macro [new] executor_service_method_auto_terminate_question
|
180
|
+
#
|
181
|
+
# Is the executor auto-terminate when the application exits?
|
182
|
+
#
|
183
|
+
# @return [Boolean] `true` when auto-termination is enabled else `false`.
|
184
|
+
|
185
|
+
# @!macro [new] executor_service_method_auto_terminate_setter
|
186
|
+
#
|
187
|
+
# Set the auto-terminate behavior for this executor.
|
188
|
+
#
|
189
|
+
# @param [Boolean] value The new auto-terminate value to set for this executor.
|
190
|
+
#
|
191
|
+
# @return [Boolean] `true` when auto-termination is enabled else `false`.
|
192
|
+
|
193
|
+
|
194
|
+
|
195
|
+
|
196
|
+
|
197
|
+
# @!macro [new] abstract_executor_service_public_api
|
198
|
+
#
|
199
|
+
# @!macro executor_service_public_api
|
200
|
+
#
|
201
|
+
# @!attribute [r] fallback_policy
|
202
|
+
# @!macro executor_service_attr_reader_fallback_policy
|
203
|
+
#
|
204
|
+
# @!method shutdown
|
205
|
+
# @!macro executor_service_method_shutdown
|
206
|
+
#
|
207
|
+
# @!method kill
|
208
|
+
# @!macro executor_service_method_kill
|
209
|
+
#
|
210
|
+
# @!method wait_for_termination(timeout = nil)
|
211
|
+
# @!macro executor_service_method_wait_for_termination
|
212
|
+
#
|
213
|
+
# @!method running?
|
214
|
+
# @!macro executor_service_method_running_question
|
215
|
+
#
|
216
|
+
# @!method shuttingdown?
|
217
|
+
# @!macro executor_service_method_shuttingdown_question
|
218
|
+
#
|
219
|
+
# @!method shutdown?
|
220
|
+
# @!macro executor_service_method_shutdown_question
|
221
|
+
#
|
222
|
+
# @!method auto_terminate?
|
223
|
+
# @!macro executor_service_method_auto_terminate_question
|
224
|
+
#
|
225
|
+
# @!method auto_terminate=(value)
|
226
|
+
# @!macro executor_service_method_auto_terminate_setter
|
227
|
+
|
228
|
+
|
229
|
+
|
230
|
+
|
231
|
+
|
232
|
+
# @!macro abstract_executor_service_public_api
|
233
|
+
# @!visibility private
|
234
|
+
class AbstractExecutorService < Synchronization::Object
|
235
|
+
include ExecutorService
|
236
|
+
|
237
|
+
# The set of possible fallback policies that may be set at thread pool creation.
|
238
|
+
FALLBACK_POLICIES = [:abort, :discard, :caller_runs].freeze
|
239
|
+
|
240
|
+
# @!macro [attach] executor_service_attr_reader_fallback_policy
|
241
|
+
attr_reader :fallback_policy
|
242
|
+
|
243
|
+
# Create a new thread pool.
|
244
|
+
def initialize(*args, &block)
|
245
|
+
super(&nil)
|
246
|
+
synchronize { ns_initialize(*args, &block) }
|
247
|
+
end
|
248
|
+
|
249
|
+
# @!macro [attach] executor_service_method_shutdown
|
250
|
+
def shutdown
|
251
|
+
raise NotImplementedError
|
252
|
+
end
|
253
|
+
|
254
|
+
# @!macro [attach] executor_service_method_kill
|
255
|
+
def kill
|
256
|
+
raise NotImplementedError
|
257
|
+
end
|
258
|
+
|
259
|
+
# @!macro [attach] executor_service_method_wait_for_termination
|
260
|
+
def wait_for_termination(timeout = nil)
|
261
|
+
raise NotImplementedError
|
262
|
+
end
|
263
|
+
|
264
|
+
# @!macro [attach] executor_service_method_running_question
|
265
|
+
def running?
|
266
|
+
synchronize { ns_running? }
|
267
|
+
end
|
268
|
+
|
269
|
+
# @!macro [attach] executor_service_method_shuttingdown_question
|
270
|
+
def shuttingdown?
|
271
|
+
synchronize { ns_shuttingdown? }
|
272
|
+
end
|
273
|
+
|
274
|
+
# @!macro [attach] executor_service_method_shutdown_question
|
275
|
+
def shutdown?
|
276
|
+
synchronize { ns_shutdown? }
|
277
|
+
end
|
278
|
+
|
279
|
+
# @!macro [attach] executor_service_method_auto_terminate_question
|
280
|
+
def auto_terminate?
|
281
|
+
synchronize { ns_auto_terminate? }
|
282
|
+
end
|
283
|
+
|
284
|
+
# @!macro [attach] executor_service_method_auto_terminate_setter
|
285
|
+
def auto_terminate=(value)
|
286
|
+
synchronize { self.ns_auto_terminate = value }
|
287
|
+
end
|
288
|
+
|
289
|
+
protected
|
290
|
+
|
291
|
+
# Handler which executes the `fallback_policy` once the queue size
|
292
|
+
# reaches `max_queue`.
|
293
|
+
#
|
294
|
+
# @param [Array] args the arguments to the task which is being handled.
|
295
|
+
#
|
296
|
+
# @!visibility private
|
297
|
+
def handle_fallback(*args)
|
298
|
+
case fallback_policy
|
299
|
+
when :abort
|
300
|
+
raise RejectedExecutionError
|
301
|
+
when :discard
|
302
|
+
false
|
303
|
+
when :caller_runs
|
304
|
+
begin
|
305
|
+
yield(*args)
|
306
|
+
rescue => ex
|
307
|
+
# let it fail
|
308
|
+
log DEBUG, ex
|
309
|
+
end
|
310
|
+
true
|
311
|
+
else
|
312
|
+
fail "Unknown fallback policy #{fallback_policy}"
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
def execute(*args, &task)
|
317
|
+
raise NotImplementedError
|
318
|
+
end
|
319
|
+
|
320
|
+
# @!macro [attach] executor_service_method_shutdown_execution
|
321
|
+
#
|
322
|
+
# Callback method called when an orderly shutdown has completed.
|
323
|
+
# The default behavior is to signal all waiting threads.
|
324
|
+
def shutdown_execution
|
325
|
+
# do nothing
|
326
|
+
end
|
327
|
+
|
328
|
+
# @!macro [attach] executor_service_method_kill_execution
|
329
|
+
#
|
330
|
+
# Callback method called when the executor has been killed.
|
331
|
+
# The default behavior is to do nothing.
|
332
|
+
def kill_execution
|
333
|
+
# do nothing
|
334
|
+
end
|
335
|
+
|
336
|
+
protected
|
337
|
+
|
338
|
+
def ns_auto_terminate?
|
339
|
+
!!@auto_terminate
|
340
|
+
end
|
341
|
+
|
342
|
+
def ns_auto_terminate=(value)
|
343
|
+
case value
|
344
|
+
when true
|
345
|
+
AtExit.add(self) { terminate_at_exit }
|
346
|
+
@auto_terminate = true
|
347
|
+
when false
|
348
|
+
AtExit.delete(self)
|
349
|
+
@auto_terminate = false
|
350
|
+
else
|
351
|
+
raise ArgumentError
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
def terminate_at_exit
|
356
|
+
kill # TODO be gentle first
|
357
|
+
wait_for_termination(10)
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
# @!macro abstract_executor_service_public_api
|
362
|
+
# @!visibility private
|
363
|
+
class RubyExecutorService < AbstractExecutorService
|
364
|
+
|
365
|
+
def initialize(*args, &block)
|
366
|
+
super
|
367
|
+
@stop_event = Event.new
|
368
|
+
@stopped_event = Event.new
|
369
|
+
ensure_ivar_visibility!
|
370
|
+
end
|
371
|
+
|
372
|
+
def post(*args, &task)
|
373
|
+
raise ArgumentError.new('no block given') unless block_given?
|
374
|
+
synchronize do
|
375
|
+
# If the executor is shut down, reject this task
|
376
|
+
return handle_fallback(*args, &task) unless running?
|
377
|
+
execute(*args, &task)
|
378
|
+
true
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
def shutdown
|
383
|
+
synchronize do
|
384
|
+
break unless running?
|
385
|
+
self.ns_auto_terminate = false
|
386
|
+
stop_event.set
|
387
|
+
shutdown_execution
|
388
|
+
end
|
389
|
+
true
|
390
|
+
end
|
391
|
+
|
392
|
+
def kill
|
393
|
+
synchronize do
|
394
|
+
break if shutdown?
|
395
|
+
self.ns_auto_terminate = false
|
396
|
+
stop_event.set
|
397
|
+
kill_execution
|
398
|
+
stopped_event.set
|
399
|
+
end
|
400
|
+
true
|
401
|
+
end
|
402
|
+
|
403
|
+
def wait_for_termination(timeout = nil)
|
404
|
+
stopped_event.wait(timeout)
|
405
|
+
end
|
406
|
+
|
407
|
+
protected
|
408
|
+
|
409
|
+
attr_reader :stop_event, :stopped_event
|
410
|
+
|
411
|
+
def shutdown_execution
|
412
|
+
stopped_event.set
|
413
|
+
end
|
414
|
+
|
415
|
+
def ns_running?
|
416
|
+
!stop_event.set?
|
417
|
+
end
|
418
|
+
|
419
|
+
def ns_shuttingdown?
|
420
|
+
!(ns_running? || ns_shutdown?)
|
421
|
+
end
|
422
|
+
|
423
|
+
def ns_shutdown?
|
424
|
+
stopped_event.set?
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
if Concurrent.on_jruby?
|
429
|
+
|
430
|
+
# @!macro abstract_executor_service_public_api
|
431
|
+
# @!visibility private
|
432
|
+
class JavaExecutorService < AbstractExecutorService
|
433
|
+
java_import 'java.lang.Runnable'
|
434
|
+
|
435
|
+
FALLBACK_POLICY_CLASSES = {
|
436
|
+
abort: java.util.concurrent.ThreadPoolExecutor::AbortPolicy,
|
437
|
+
discard: java.util.concurrent.ThreadPoolExecutor::DiscardPolicy,
|
438
|
+
caller_runs: java.util.concurrent.ThreadPoolExecutor::CallerRunsPolicy
|
439
|
+
}.freeze
|
440
|
+
private_constant :FALLBACK_POLICY_CLASSES
|
441
|
+
|
442
|
+
def initialize(*args, &block)
|
443
|
+
super
|
444
|
+
ns_make_executor_runnable
|
445
|
+
end
|
446
|
+
|
447
|
+
def post(*args, &task)
|
448
|
+
raise ArgumentError.new('no block given') unless block_given?
|
449
|
+
return handle_fallback(*args, &task) unless running?
|
450
|
+
@executor.submit_runnable Job.new(args, task)
|
451
|
+
true
|
452
|
+
rescue Java::JavaUtilConcurrent::RejectedExecutionException
|
453
|
+
raise RejectedExecutionError
|
454
|
+
end
|
455
|
+
|
456
|
+
def wait_for_termination(timeout = nil)
|
457
|
+
if timeout.nil?
|
458
|
+
ok = @executor.awaitTermination(60, java.util.concurrent.TimeUnit::SECONDS) until ok
|
459
|
+
true
|
460
|
+
else
|
461
|
+
@executor.awaitTermination(1000 * timeout, java.util.concurrent.TimeUnit::MILLISECONDS)
|
462
|
+
end
|
463
|
+
end
|
464
|
+
|
465
|
+
def shutdown
|
466
|
+
synchronize do
|
467
|
+
self.ns_auto_terminate = false
|
468
|
+
@executor.shutdown
|
469
|
+
nil
|
470
|
+
end
|
471
|
+
end
|
472
|
+
|
473
|
+
def kill
|
474
|
+
synchronize do
|
475
|
+
self.ns_auto_terminate = false
|
476
|
+
@executor.shutdownNow
|
477
|
+
nil
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
481
|
+
protected
|
482
|
+
|
483
|
+
def ns_running?
|
484
|
+
!(ns_shuttingdown? || ns_shutdown?)
|
485
|
+
end
|
486
|
+
|
487
|
+
def ns_shuttingdown?
|
488
|
+
if @executor.respond_to? :isTerminating
|
489
|
+
@executor.isTerminating
|
490
|
+
else
|
491
|
+
false
|
492
|
+
end
|
493
|
+
end
|
494
|
+
|
495
|
+
def ns_shutdown?
|
496
|
+
@executor.isShutdown || @executor.isTerminated
|
497
|
+
end
|
498
|
+
|
499
|
+
def ns_make_executor_runnable
|
500
|
+
if !defined?(@executor.submit_runnable)
|
501
|
+
@executor.class.class_eval do
|
502
|
+
java_alias :submit_runnable, :submit, [java.lang.Runnable.java_class]
|
503
|
+
end
|
504
|
+
end
|
505
|
+
end
|
506
|
+
|
507
|
+
class Job
|
508
|
+
include Runnable
|
509
|
+
def initialize(args, block)
|
510
|
+
@args = args
|
511
|
+
@block = block
|
512
|
+
end
|
513
|
+
|
514
|
+
def run
|
515
|
+
@block.call(*@args)
|
516
|
+
end
|
517
|
+
end
|
518
|
+
private_constant :Job
|
519
|
+
end
|
520
|
+
end
|
521
|
+
end
|