concurrent-ruby 0.7.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. data/LICENSE.txt +21 -0
  2. data/README.md +217 -0
  3. data/lib/concurrent.rb +45 -0
  4. data/lib/concurrent/actor.rb +104 -0
  5. data/lib/concurrent/actor/behaviour.rb +70 -0
  6. data/lib/concurrent/actor/behaviour/abstract.rb +48 -0
  7. data/lib/concurrent/actor/behaviour/awaits.rb +21 -0
  8. data/lib/concurrent/actor/behaviour/buffer.rb +54 -0
  9. data/lib/concurrent/actor/behaviour/errors_on_unknown_message.rb +12 -0
  10. data/lib/concurrent/actor/behaviour/executes_context.rb +18 -0
  11. data/lib/concurrent/actor/behaviour/linking.rb +42 -0
  12. data/lib/concurrent/actor/behaviour/pausing.rb +77 -0
  13. data/lib/concurrent/actor/behaviour/removes_child.rb +16 -0
  14. data/lib/concurrent/actor/behaviour/sets_results.rb +36 -0
  15. data/lib/concurrent/actor/behaviour/supervised.rb +58 -0
  16. data/lib/concurrent/actor/behaviour/supervising.rb +34 -0
  17. data/lib/concurrent/actor/behaviour/terminates_children.rb +13 -0
  18. data/lib/concurrent/actor/behaviour/termination.rb +54 -0
  19. data/lib/concurrent/actor/context.rb +153 -0
  20. data/lib/concurrent/actor/core.rb +213 -0
  21. data/lib/concurrent/actor/default_dead_letter_handler.rb +9 -0
  22. data/lib/concurrent/actor/envelope.rb +41 -0
  23. data/lib/concurrent/actor/errors.rb +27 -0
  24. data/lib/concurrent/actor/internal_delegations.rb +49 -0
  25. data/lib/concurrent/actor/public_delegations.rb +40 -0
  26. data/lib/concurrent/actor/reference.rb +81 -0
  27. data/lib/concurrent/actor/root.rb +37 -0
  28. data/lib/concurrent/actor/type_check.rb +48 -0
  29. data/lib/concurrent/actor/utils.rb +10 -0
  30. data/lib/concurrent/actor/utils/ad_hoc.rb +21 -0
  31. data/lib/concurrent/actor/utils/balancer.rb +40 -0
  32. data/lib/concurrent/actor/utils/broadcast.rb +52 -0
  33. data/lib/concurrent/actor/utils/pool.rb +59 -0
  34. data/lib/concurrent/actress.rb +3 -0
  35. data/lib/concurrent/agent.rb +230 -0
  36. data/lib/concurrent/async.rb +284 -0
  37. data/lib/concurrent/atomic.rb +91 -0
  38. data/lib/concurrent/atomic/atomic_boolean.rb +202 -0
  39. data/lib/concurrent/atomic/atomic_fixnum.rb +203 -0
  40. data/lib/concurrent/atomic/condition.rb +67 -0
  41. data/lib/concurrent/atomic/copy_on_notify_observer_set.rb +118 -0
  42. data/lib/concurrent/atomic/copy_on_write_observer_set.rb +117 -0
  43. data/lib/concurrent/atomic/count_down_latch.rb +116 -0
  44. data/lib/concurrent/atomic/cyclic_barrier.rb +106 -0
  45. data/lib/concurrent/atomic/event.rb +98 -0
  46. data/lib/concurrent/atomic/synchronization.rb +51 -0
  47. data/lib/concurrent/atomic/thread_local_var.rb +82 -0
  48. data/lib/concurrent/atomic_reference/concurrent_update_error.rb +8 -0
  49. data/lib/concurrent/atomic_reference/direct_update.rb +50 -0
  50. data/lib/concurrent/atomic_reference/jruby.rb +14 -0
  51. data/lib/concurrent/atomic_reference/mutex_atomic.rb +77 -0
  52. data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +25 -0
  53. data/lib/concurrent/atomic_reference/rbx.rb +19 -0
  54. data/lib/concurrent/atomic_reference/ruby.rb +37 -0
  55. data/lib/concurrent/atomics.rb +11 -0
  56. data/lib/concurrent/channel/buffered_channel.rb +85 -0
  57. data/lib/concurrent/channel/channel.rb +41 -0
  58. data/lib/concurrent/channel/unbuffered_channel.rb +35 -0
  59. data/lib/concurrent/channel/waitable_list.rb +40 -0
  60. data/lib/concurrent/channels.rb +5 -0
  61. data/lib/concurrent/collection/blocking_ring_buffer.rb +71 -0
  62. data/lib/concurrent/collection/priority_queue.rb +305 -0
  63. data/lib/concurrent/collection/ring_buffer.rb +59 -0
  64. data/lib/concurrent/collections.rb +3 -0
  65. data/lib/concurrent/configuration.rb +161 -0
  66. data/lib/concurrent/dataflow.rb +108 -0
  67. data/lib/concurrent/delay.rb +104 -0
  68. data/lib/concurrent/dereferenceable.rb +101 -0
  69. data/lib/concurrent/errors.rb +30 -0
  70. data/lib/concurrent/exchanger.rb +34 -0
  71. data/lib/concurrent/executor/cached_thread_pool.rb +44 -0
  72. data/lib/concurrent/executor/executor.rb +282 -0
  73. data/lib/concurrent/executor/fixed_thread_pool.rb +33 -0
  74. data/lib/concurrent/executor/immediate_executor.rb +65 -0
  75. data/lib/concurrent/executor/java_cached_thread_pool.rb +31 -0
  76. data/lib/concurrent/executor/java_fixed_thread_pool.rb +41 -0
  77. data/lib/concurrent/executor/java_single_thread_executor.rb +22 -0
  78. data/lib/concurrent/executor/java_thread_pool_executor.rb +180 -0
  79. data/lib/concurrent/executor/per_thread_executor.rb +100 -0
  80. data/lib/concurrent/executor/ruby_cached_thread_pool.rb +29 -0
  81. data/lib/concurrent/executor/ruby_fixed_thread_pool.rb +32 -0
  82. data/lib/concurrent/executor/ruby_single_thread_executor.rb +74 -0
  83. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +288 -0
  84. data/lib/concurrent/executor/ruby_thread_pool_worker.rb +72 -0
  85. data/lib/concurrent/executor/safe_task_executor.rb +35 -0
  86. data/lib/concurrent/executor/serialized_execution.rb +126 -0
  87. data/lib/concurrent/executor/single_thread_executor.rb +35 -0
  88. data/lib/concurrent/executor/thread_pool_executor.rb +68 -0
  89. data/lib/concurrent/executor/timer_set.rb +143 -0
  90. data/lib/concurrent/executors.rb +9 -0
  91. data/lib/concurrent/future.rb +125 -0
  92. data/lib/concurrent/ivar.rb +111 -0
  93. data/lib/concurrent/lazy_register.rb +58 -0
  94. data/lib/concurrent/logging.rb +17 -0
  95. data/lib/concurrent/mvar.rb +200 -0
  96. data/lib/concurrent/obligation.rb +171 -0
  97. data/lib/concurrent/observable.rb +40 -0
  98. data/lib/concurrent/options_parser.rb +48 -0
  99. data/lib/concurrent/promise.rb +170 -0
  100. data/lib/concurrent/scheduled_task.rb +79 -0
  101. data/lib/concurrent/timer_task.rb +341 -0
  102. data/lib/concurrent/tvar.rb +248 -0
  103. data/lib/concurrent/utilities.rb +3 -0
  104. data/lib/concurrent/utility/processor_count.rb +152 -0
  105. data/lib/concurrent/utility/timeout.rb +35 -0
  106. data/lib/concurrent/utility/timer.rb +21 -0
  107. data/lib/concurrent/version.rb +3 -0
  108. data/lib/concurrent_ruby.rb +1 -0
  109. data/lib/concurrent_ruby_ext.jar +0 -0
  110. data/lib/concurrent_ruby_ext.so +0 -0
  111. data/lib/extension_helper.rb +28 -0
  112. metadata +163 -0
@@ -0,0 +1,30 @@
1
+ module Concurrent
2
+
3
+ # Raised when errors occur during configuration.
4
+ ConfigurationError = Class.new(StandardError)
5
+
6
+ # Raised when a lifecycle method (such as `stop`) is called in an improper
7
+ # sequence or when the object is in an inappropriate state.
8
+ LifecycleError = Class.new(StandardError)
9
+
10
+ # Raised when an object's methods are called when it has not been
11
+ # properly initialized.
12
+ InitializationError = Class.new(StandardError)
13
+
14
+ # Raised when an object with a start/stop lifecycle has been started an
15
+ # excessive number of times. Often used in conjunction with a restart
16
+ # policy or strategy.
17
+ MaxRestartFrequencyError = Class.new(StandardError)
18
+
19
+ # Raised when an attempt is made to modify an immutable object
20
+ # (such as an `IVar`) after its final state has been set.
21
+ MultipleAssignmentError = Class.new(StandardError)
22
+
23
+ # Raised by an `Executor` when it is unable to process a given task,
24
+ # possibly because of a reject policy or other internal error.
25
+ RejectedExecutionError = Class.new(StandardError)
26
+
27
+ # Raised when an operation times out.
28
+ TimeoutError = Class.new(StandardError)
29
+
30
+ end
@@ -0,0 +1,34 @@
1
+ module Concurrent
2
+ class Exchanger
3
+
4
+ EMPTY = Object.new
5
+
6
+ def initialize(opts = {})
7
+ @first = MVar.new(EMPTY, opts)
8
+ @second = MVar.new(MVar::EMPTY, opts)
9
+ end
10
+
11
+ # @param [Object] value the value to exchange with an other thread
12
+ # @param [Numeric] timeout the maximum time in second to wait for one other thread. nil (default value) means no timeout
13
+ # @return [Object] the value exchanged by the other thread; nil if timed out
14
+ def exchange(value, timeout = nil)
15
+ first = @first.take(timeout)
16
+ if first == MVar::TIMEOUT
17
+ nil
18
+ elsif first == EMPTY
19
+ @first.put value
20
+ second = @second.take timeout
21
+ if second == MVar::TIMEOUT
22
+ nil
23
+ else
24
+ second
25
+ end
26
+ else
27
+ @first.put EMPTY
28
+ @second.put value
29
+ first
30
+ end
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,44 @@
1
+ require 'concurrent/executor/ruby_cached_thread_pool'
2
+
3
+ module Concurrent
4
+
5
+ if RUBY_PLATFORM == 'java'
6
+ require 'concurrent/executor/java_cached_thread_pool'
7
+ # @!macro [attach] cached_thread_pool
8
+ # A thread pool that dynamically grows and shrinks to fit the current workload.
9
+ # New threads are created as needed, existing threads are reused, and threads
10
+ # that remain idle for too long are killed and removed from the pool. These
11
+ # pools are particularly suited to applications that perform a high volume of
12
+ # short-lived tasks.
13
+ #
14
+ # On creation a `CachedThreadPool` has zero running threads. New threads are
15
+ # created on the pool as new operations are `#post`. The size of the pool
16
+ # will grow until `#max_length` threads are in the pool or until the number
17
+ # of threads exceeds the number of running and pending operations. When a new
18
+ # operation is post to the pool the first available idle thread will be tasked
19
+ # with the new operation.
20
+ #
21
+ # Should a thread crash for any reason the thread will immediately be removed
22
+ # from the pool. Similarly, threads which remain idle for an extended period
23
+ # of time will be killed and reclaimed. Thus these thread pools are very
24
+ # efficient at reclaiming unused resources.
25
+ #
26
+ # The API and behavior of this class are based on Java's `CachedThreadPool`
27
+ #
28
+ # @note When running on the JVM (JRuby) this class will inherit from `JavaCachedThreadPool`.
29
+ # On all other platforms it will inherit from `RubyCachedThreadPool`.
30
+ #
31
+ # @see Concurrent::RubyCachedThreadPool
32
+ # @see Concurrent::JavaCachedThreadPool
33
+ #
34
+ # @see http://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html
35
+ # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html
36
+ # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html
37
+ class CachedThreadPool < JavaCachedThreadPool
38
+ end
39
+ else
40
+ # @!macro cached_thread_pool
41
+ class CachedThreadPool < RubyCachedThreadPool
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,282 @@
1
+ require 'concurrent/errors'
2
+ require 'concurrent/logging'
3
+ require 'concurrent/atomic/event'
4
+
5
+ module Concurrent
6
+
7
+ module Executor
8
+
9
+ # @!macro [attach] executor_module_method_can_overflow_question
10
+ #
11
+ # Does the task queue have a maximum size?
12
+ #
13
+ # @return [Boolean] True if the task queue has a maximum size else false.
14
+ #
15
+ # @note Always returns `false`
16
+ def can_overflow?
17
+ false
18
+ end
19
+
20
+ # @!macro [attach] executor_module_method_serialized_question
21
+ #
22
+ # Does this executor guarantee serialization of its operations?
23
+ #
24
+ # @return [Boolean] True if the executor guarantees that all operations
25
+ # will be post in the order they are received and no two operations may
26
+ # occur simultaneously. Else false.
27
+ #
28
+ # @note Always returns `false`
29
+ def serialized?
30
+ false
31
+ end
32
+ end
33
+
34
+ # Indicates that the including `Executor` or `ExecutorService` guarantees
35
+ # that all operations will occur in the order they are post and that no
36
+ # two operations may occur simultaneously. This module provides no
37
+ # functionality and provides no guarantees. That is the responsibility
38
+ # of the including class. This module exists solely to allow the including
39
+ # object to be interrogated for its serialization status.
40
+ #
41
+ # @example
42
+ # class Foo
43
+ # include Concurrent::SerialExecutor
44
+ # end
45
+ #
46
+ # foo = Foo.new
47
+ #
48
+ # foo.is_a? Concurrent::Executor #=> true
49
+ # foo.is_a? Concurrent::SerialExecutor #=> true
50
+ # foo.serialized? #=> true
51
+ module SerialExecutor
52
+ include Executor
53
+
54
+ # @!macro executor_module_method_serialized_question
55
+ #
56
+ # @note Always returns `true`
57
+ def serialized?
58
+ true
59
+ end
60
+ end
61
+
62
+ module RubyExecutor
63
+ include Executor
64
+ include Logging
65
+
66
+ # @!macro [attach] executor_method_post
67
+ #
68
+ # Submit a task to the executor for asynchronous processing.
69
+ #
70
+ # @param [Array] args zero or more arguments to be passed to the task
71
+ #
72
+ # @yield the asynchronous task to perform
73
+ #
74
+ # @return [Boolean] `true` if the task is queued, `false` if the executor
75
+ # is not running
76
+ #
77
+ # @raise [ArgumentError] if no task is given
78
+ def post(*args, &task)
79
+ raise ArgumentError.new('no block given') unless block_given?
80
+ mutex.synchronize do
81
+ return false unless running?
82
+ execute(*args, &task)
83
+ true
84
+ end
85
+ end
86
+
87
+ # @!macro [attach] executor_method_left_shift
88
+ #
89
+ # Submit a task to the executor for asynchronous processing.
90
+ #
91
+ # @param [Proc] task the asynchronous task to perform
92
+ #
93
+ # @return [self] returns itself
94
+ def <<(task)
95
+ post(&task)
96
+ self
97
+ end
98
+
99
+ # @!macro [attach] executor_method_running_question
100
+ #
101
+ # Is the executor running?
102
+ #
103
+ # @return [Boolean] `true` when running, `false` when shutting down or shutdown
104
+ def running?
105
+ ! stop_event.set?
106
+ end
107
+
108
+ # @!macro [attach] executor_method_shuttingdown_question
109
+ #
110
+ # Is the executor shuttingdown?
111
+ #
112
+ # @return [Boolean] `true` when not running and not shutdown, else `false`
113
+ def shuttingdown?
114
+ ! (running? || shutdown?)
115
+ end
116
+
117
+ # @!macro [attach] executor_method_shutdown_question
118
+ #
119
+ # Is the executor shutdown?
120
+ #
121
+ # @return [Boolean] `true` when shutdown, `false` when shutting down or running
122
+ def shutdown?
123
+ stopped_event.set?
124
+ end
125
+
126
+ # @!macro [attach] executor_method_shutdown
127
+ #
128
+ # Begin an orderly shutdown. Tasks already in the queue will be executed,
129
+ # but no new tasks will be accepted. Has no additional effect if the
130
+ # thread pool is not running.
131
+ def shutdown
132
+ mutex.synchronize do
133
+ break unless running?
134
+ stop_event.set
135
+ shutdown_execution
136
+ end
137
+ true
138
+ end
139
+
140
+ # @!macro [attach] executor_method_kill
141
+ #
142
+ # Begin an immediate shutdown. In-progress tasks will be allowed to
143
+ # complete but enqueued tasks will be dismissed and no new tasks
144
+ # will be accepted. Has no additional effect if the thread pool is
145
+ # not running.
146
+ def kill
147
+ mutex.synchronize do
148
+ break if shutdown?
149
+ stop_event.set
150
+ kill_execution
151
+ stopped_event.set
152
+ end
153
+ true
154
+ end
155
+
156
+ # @!macro [attach] executor_method_wait_for_termination
157
+ #
158
+ # Block until executor shutdown is complete or until `timeout` seconds have
159
+ # passed.
160
+ #
161
+ # @note Does not initiate shutdown or termination. Either `shutdown` or `kill`
162
+ # must be called before this method (or on another thread).
163
+ #
164
+ # @param [Integer] timeout the maximum number of seconds to wait for shutdown to complete
165
+ #
166
+ # @return [Boolean] `true` if shutdown complete or false on `timeout`
167
+ def wait_for_termination(timeout = nil)
168
+ stopped_event.wait(timeout)
169
+ end
170
+
171
+ protected
172
+
173
+ attr_reader :mutex, :stop_event, :stopped_event
174
+
175
+ # @!macro [attach] executor_method_init_executor
176
+ #
177
+ # Initialize the executor by creating and initializing all the
178
+ # internal synchronization objects.
179
+ def init_executor
180
+ @mutex = Mutex.new
181
+ @stop_event = Event.new
182
+ @stopped_event = Event.new
183
+ end
184
+
185
+ # @!macro [attach] executor_method_execute
186
+ def execute(*args, &task)
187
+ raise NotImplementedError
188
+ end
189
+
190
+ # @!macro [attach] executor_method_shutdown_execution
191
+ #
192
+ # Callback method called when an orderly shutdown has completed.
193
+ # The default behavior is to signal all waiting threads.
194
+ def shutdown_execution
195
+ stopped_event.set
196
+ end
197
+
198
+ # @!macro [attach] executor_method_kill_execution
199
+ #
200
+ # Callback method called when the executor has been killed.
201
+ # The default behavior is to do nothing.
202
+ def kill_execution
203
+ # do nothing
204
+ end
205
+ end
206
+
207
+ if RUBY_PLATFORM == 'java'
208
+
209
+ module JavaExecutor
210
+ include Executor
211
+ java_import 'java.lang.Runnable'
212
+
213
+ # @!macro executor_method_post
214
+ def post(*args)
215
+ raise ArgumentError.new('no block given') unless block_given?
216
+ if running?
217
+ executor_submit = @executor.java_method(:submit, [Runnable.java_class])
218
+ executor_submit.call { yield(*args) }
219
+ true
220
+ else
221
+ false
222
+ end
223
+ rescue Java::JavaUtilConcurrent::RejectedExecutionException
224
+ raise RejectedExecutionError
225
+ end
226
+
227
+ # @!macro executor_method_left_shift
228
+ def <<(task)
229
+ post(&task)
230
+ self
231
+ end
232
+
233
+ # @!macro executor_method_running_question
234
+ def running?
235
+ ! (shuttingdown? || shutdown?)
236
+ end
237
+
238
+ # @!macro executor_method_shuttingdown_question
239
+ def shuttingdown?
240
+ if @executor.respond_to? :isTerminating
241
+ @executor.isTerminating
242
+ else
243
+ false
244
+ end
245
+ end
246
+
247
+ # @!macro executor_method_shutdown_question
248
+ def shutdown?
249
+ @executor.isShutdown || @executor.isTerminated
250
+ end
251
+
252
+ # @!macro executor_method_wait_for_termination
253
+ def wait_for_termination(timeout = nil)
254
+ if timeout.nil?
255
+ ok = @executor.awaitTermination(60, java.util.concurrent.TimeUnit::SECONDS) until ok
256
+ true
257
+ else
258
+ @executor.awaitTermination(1000 * timeout, java.util.concurrent.TimeUnit::MILLISECONDS)
259
+ end
260
+ end
261
+
262
+ # @!macro executor_method_shutdown
263
+ def shutdown
264
+ @executor.shutdown
265
+ nil
266
+ end
267
+
268
+ # @!macro executor_method_kill
269
+ def kill
270
+ @executor.shutdownNow
271
+ nil
272
+ end
273
+
274
+ protected
275
+
276
+ def set_shutdown_hook
277
+ # without this the process may fail to exit
278
+ at_exit { self.kill }
279
+ end
280
+ end
281
+ end
282
+ end
@@ -0,0 +1,33 @@
1
+ require 'concurrent/executor/ruby_fixed_thread_pool'
2
+
3
+ module Concurrent
4
+
5
+ if RUBY_PLATFORM == 'java'
6
+ require 'concurrent/executor/java_fixed_thread_pool'
7
+ # @!macro [attach] fixed_thread_pool
8
+ #
9
+ # A thread pool with a set number of threads. The number of threads in the pool
10
+ # is set on construction and remains constant. When all threads are busy new
11
+ # tasks `#post` to the thread pool are enqueued until a thread becomes available.
12
+ # Should a thread crash for any reason the thread will immediately be removed
13
+ # from the pool and replaced.
14
+ #
15
+ # The API and behavior of this class are based on Java's `FixedThreadPool`
16
+ #
17
+ # @note When running on the JVM (JRuby) this class will inherit from `JavaFixedThreadPool`.
18
+ # On all other platforms it will inherit from `RubyFixedThreadPool`.
19
+ #
20
+ # @see Concurrent::RubyFixedThreadPool
21
+ # @see Concurrent::JavaFixedThreadPool
22
+ #
23
+ # @see http://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html
24
+ # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html
25
+ # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html
26
+ class FixedThreadPool < JavaFixedThreadPool
27
+ end
28
+ else
29
+ # @!macro fixed_thread_pool
30
+ class FixedThreadPool < RubyFixedThreadPool
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,65 @@
1
+ require 'concurrent/atomic/event'
2
+ require 'concurrent/executor/executor'
3
+
4
+ module Concurrent
5
+
6
+ # An executor service which runs all operations on the current thread,
7
+ # blocking as necessary. Operations are performed in the order they are
8
+ # received and no two operations can be performed simultaneously.
9
+ #
10
+ # This executor service exists mainly for testing an debugging. When used
11
+ # it immediately runs every `#post` operation on the current thread, blocking
12
+ # that thread until the operation is complete. This can be very beneficial
13
+ # during testing because it makes all operations deterministic.
14
+ #
15
+ # @note Intended for use primarily in testing and debugging.
16
+ class ImmediateExecutor
17
+ include SerialExecutor
18
+
19
+ # Creates a new executor
20
+ def initialize
21
+ @stopped = Concurrent::Event.new
22
+ end
23
+
24
+ # @!macro executor_method_post
25
+ def post(*args, &task)
26
+ raise ArgumentError.new('no block given') unless block_given?
27
+ return false unless running?
28
+ task.call(*args)
29
+ true
30
+ end
31
+
32
+ # @!macro executor_method_left_shift
33
+ def <<(task)
34
+ post(&task)
35
+ self
36
+ end
37
+
38
+ # @!macro executor_method_running_question
39
+ def running?
40
+ ! shutdown?
41
+ end
42
+
43
+ # @!macro executor_method_shuttingdown_question
44
+ def shuttingdown?
45
+ false
46
+ end
47
+
48
+ # @!macro executor_method_shutdown_question
49
+ def shutdown?
50
+ @stopped.set?
51
+ end
52
+
53
+ # @!macro executor_method_shutdown
54
+ def shutdown
55
+ @stopped.set
56
+ true
57
+ end
58
+ alias_method :kill, :shutdown
59
+
60
+ # @!macro executor_method_wait_for_termination
61
+ def wait_for_termination(timeout = nil)
62
+ @stopped.wait(timeout)
63
+ end
64
+ end
65
+ end