o-concurrent-ruby 1.1.11

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.
Files changed (142) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +542 -0
  3. data/Gemfile +37 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +404 -0
  6. data/Rakefile +307 -0
  7. data/ext/concurrent-ruby/ConcurrentRubyService.java +17 -0
  8. data/ext/concurrent-ruby/com/concurrent_ruby/ext/AtomicReferenceLibrary.java +175 -0
  9. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JRubyMapBackendLibrary.java +248 -0
  10. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicBooleanLibrary.java +93 -0
  11. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java +113 -0
  12. data/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java +189 -0
  13. data/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java +307 -0
  14. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMap.java +31 -0
  15. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMapV8.java +3863 -0
  16. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/LongAdder.java +203 -0
  17. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/Striped64.java +342 -0
  18. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/ConcurrentHashMapV8.java +3800 -0
  19. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/LongAdder.java +204 -0
  20. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/Striped64.java +291 -0
  21. data/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166y/ThreadLocalRandom.java +199 -0
  22. data/lib/concurrent-ruby/concurrent/agent.rb +587 -0
  23. data/lib/concurrent-ruby/concurrent/array.rb +66 -0
  24. data/lib/concurrent-ruby/concurrent/async.rb +449 -0
  25. data/lib/concurrent-ruby/concurrent/atom.rb +222 -0
  26. data/lib/concurrent-ruby/concurrent/atomic/abstract_thread_local_var.rb +66 -0
  27. data/lib/concurrent-ruby/concurrent/atomic/atomic_boolean.rb +126 -0
  28. data/lib/concurrent-ruby/concurrent/atomic/atomic_fixnum.rb +143 -0
  29. data/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb +164 -0
  30. data/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb +205 -0
  31. data/lib/concurrent-ruby/concurrent/atomic/count_down_latch.rb +100 -0
  32. data/lib/concurrent-ruby/concurrent/atomic/cyclic_barrier.rb +128 -0
  33. data/lib/concurrent-ruby/concurrent/atomic/event.rb +109 -0
  34. data/lib/concurrent-ruby/concurrent/atomic/java_count_down_latch.rb +42 -0
  35. data/lib/concurrent-ruby/concurrent/atomic/java_thread_local_var.rb +37 -0
  36. data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_boolean.rb +62 -0
  37. data/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb +75 -0
  38. data/lib/concurrent-ruby/concurrent/atomic/mutex_count_down_latch.rb +44 -0
  39. data/lib/concurrent-ruby/concurrent/atomic/mutex_semaphore.rb +131 -0
  40. data/lib/concurrent-ruby/concurrent/atomic/read_write_lock.rb +254 -0
  41. data/lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb +377 -0
  42. data/lib/concurrent-ruby/concurrent/atomic/ruby_thread_local_var.rb +181 -0
  43. data/lib/concurrent-ruby/concurrent/atomic/semaphore.rb +166 -0
  44. data/lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb +104 -0
  45. data/lib/concurrent-ruby/concurrent/atomic_reference/mutex_atomic.rb +56 -0
  46. data/lib/concurrent-ruby/concurrent/atomic_reference/numeric_cas_wrapper.rb +28 -0
  47. data/lib/concurrent-ruby/concurrent/atomics.rb +10 -0
  48. data/lib/concurrent-ruby/concurrent/collection/copy_on_notify_observer_set.rb +107 -0
  49. data/lib/concurrent-ruby/concurrent/collection/copy_on_write_observer_set.rb +111 -0
  50. data/lib/concurrent-ruby/concurrent/collection/java_non_concurrent_priority_queue.rb +84 -0
  51. data/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb +158 -0
  52. data/lib/concurrent-ruby/concurrent/collection/map/atomic_reference_map_backend.rb +927 -0
  53. data/lib/concurrent-ruby/concurrent/collection/map/mri_map_backend.rb +66 -0
  54. data/lib/concurrent-ruby/concurrent/collection/map/non_concurrent_map_backend.rb +140 -0
  55. data/lib/concurrent-ruby/concurrent/collection/map/synchronized_map_backend.rb +82 -0
  56. data/lib/concurrent-ruby/concurrent/collection/map/truffleruby_map_backend.rb +14 -0
  57. data/lib/concurrent-ruby/concurrent/collection/non_concurrent_priority_queue.rb +143 -0
  58. data/lib/concurrent-ruby/concurrent/collection/ruby_non_concurrent_priority_queue.rb +160 -0
  59. data/lib/concurrent-ruby/concurrent/concern/deprecation.rb +34 -0
  60. data/lib/concurrent-ruby/concurrent/concern/dereferenceable.rb +73 -0
  61. data/lib/concurrent-ruby/concurrent/concern/logging.rb +32 -0
  62. data/lib/concurrent-ruby/concurrent/concern/obligation.rb +220 -0
  63. data/lib/concurrent-ruby/concurrent/concern/observable.rb +110 -0
  64. data/lib/concurrent-ruby/concurrent/configuration.rb +188 -0
  65. data/lib/concurrent-ruby/concurrent/constants.rb +8 -0
  66. data/lib/concurrent-ruby/concurrent/dataflow.rb +81 -0
  67. data/lib/concurrent-ruby/concurrent/delay.rb +199 -0
  68. data/lib/concurrent-ruby/concurrent/errors.rb +69 -0
  69. data/lib/concurrent-ruby/concurrent/exchanger.rb +352 -0
  70. data/lib/concurrent-ruby/concurrent/executor/abstract_executor_service.rb +131 -0
  71. data/lib/concurrent-ruby/concurrent/executor/cached_thread_pool.rb +62 -0
  72. data/lib/concurrent-ruby/concurrent/executor/executor_service.rb +185 -0
  73. data/lib/concurrent-ruby/concurrent/executor/fixed_thread_pool.rb +220 -0
  74. data/lib/concurrent-ruby/concurrent/executor/immediate_executor.rb +66 -0
  75. data/lib/concurrent-ruby/concurrent/executor/indirect_immediate_executor.rb +44 -0
  76. data/lib/concurrent-ruby/concurrent/executor/java_executor_service.rb +103 -0
  77. data/lib/concurrent-ruby/concurrent/executor/java_single_thread_executor.rb +30 -0
  78. data/lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb +140 -0
  79. data/lib/concurrent-ruby/concurrent/executor/ruby_executor_service.rb +82 -0
  80. data/lib/concurrent-ruby/concurrent/executor/ruby_single_thread_executor.rb +21 -0
  81. data/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb +368 -0
  82. data/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb +35 -0
  83. data/lib/concurrent-ruby/concurrent/executor/serial_executor_service.rb +34 -0
  84. data/lib/concurrent-ruby/concurrent/executor/serialized_execution.rb +107 -0
  85. data/lib/concurrent-ruby/concurrent/executor/serialized_execution_delegator.rb +28 -0
  86. data/lib/concurrent-ruby/concurrent/executor/simple_executor_service.rb +100 -0
  87. data/lib/concurrent-ruby/concurrent/executor/single_thread_executor.rb +57 -0
  88. data/lib/concurrent-ruby/concurrent/executor/thread_pool_executor.rb +88 -0
  89. data/lib/concurrent-ruby/concurrent/executor/timer_set.rb +172 -0
  90. data/lib/concurrent-ruby/concurrent/executors.rb +20 -0
  91. data/lib/concurrent-ruby/concurrent/future.rb +141 -0
  92. data/lib/concurrent-ruby/concurrent/hash.rb +59 -0
  93. data/lib/concurrent-ruby/concurrent/immutable_struct.rb +101 -0
  94. data/lib/concurrent-ruby/concurrent/ivar.rb +207 -0
  95. data/lib/concurrent-ruby/concurrent/map.rb +346 -0
  96. data/lib/concurrent-ruby/concurrent/maybe.rb +229 -0
  97. data/lib/concurrent-ruby/concurrent/mutable_struct.rb +239 -0
  98. data/lib/concurrent-ruby/concurrent/mvar.rb +242 -0
  99. data/lib/concurrent-ruby/concurrent/options.rb +42 -0
  100. data/lib/concurrent-ruby/concurrent/promise.rb +580 -0
  101. data/lib/concurrent-ruby/concurrent/promises.rb +2167 -0
  102. data/lib/concurrent-ruby/concurrent/re_include.rb +58 -0
  103. data/lib/concurrent-ruby/concurrent/scheduled_task.rb +331 -0
  104. data/lib/concurrent-ruby/concurrent/set.rb +74 -0
  105. data/lib/concurrent-ruby/concurrent/settable_struct.rb +139 -0
  106. data/lib/concurrent-ruby/concurrent/synchronization/abstract_lockable_object.rb +98 -0
  107. data/lib/concurrent-ruby/concurrent/synchronization/abstract_object.rb +24 -0
  108. data/lib/concurrent-ruby/concurrent/synchronization/abstract_struct.rb +171 -0
  109. data/lib/concurrent-ruby/concurrent/synchronization/condition.rb +60 -0
  110. data/lib/concurrent-ruby/concurrent/synchronization/jruby_lockable_object.rb +13 -0
  111. data/lib/concurrent-ruby/concurrent/synchronization/jruby_object.rb +45 -0
  112. data/lib/concurrent-ruby/concurrent/synchronization/lock.rb +36 -0
  113. data/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb +72 -0
  114. data/lib/concurrent-ruby/concurrent/synchronization/mri_object.rb +44 -0
  115. data/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb +88 -0
  116. data/lib/concurrent-ruby/concurrent/synchronization/object.rb +183 -0
  117. data/lib/concurrent-ruby/concurrent/synchronization/rbx_lockable_object.rb +71 -0
  118. data/lib/concurrent-ruby/concurrent/synchronization/rbx_object.rb +49 -0
  119. data/lib/concurrent-ruby/concurrent/synchronization/truffleruby_object.rb +47 -0
  120. data/lib/concurrent-ruby/concurrent/synchronization/volatile.rb +36 -0
  121. data/lib/concurrent-ruby/concurrent/synchronization.rb +30 -0
  122. data/lib/concurrent-ruby/concurrent/thread_safe/synchronized_delegator.rb +50 -0
  123. data/lib/concurrent-ruby/concurrent/thread_safe/util/adder.rb +74 -0
  124. data/lib/concurrent-ruby/concurrent/thread_safe/util/cheap_lockable.rb +118 -0
  125. data/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb +88 -0
  126. data/lib/concurrent-ruby/concurrent/thread_safe/util/power_of_two_tuple.rb +38 -0
  127. data/lib/concurrent-ruby/concurrent/thread_safe/util/striped64.rb +246 -0
  128. data/lib/concurrent-ruby/concurrent/thread_safe/util/volatile.rb +75 -0
  129. data/lib/concurrent-ruby/concurrent/thread_safe/util/xor_shift_random.rb +50 -0
  130. data/lib/concurrent-ruby/concurrent/thread_safe/util.rb +16 -0
  131. data/lib/concurrent-ruby/concurrent/timer_task.rb +311 -0
  132. data/lib/concurrent-ruby/concurrent/tuple.rb +86 -0
  133. data/lib/concurrent-ruby/concurrent/tvar.rb +221 -0
  134. data/lib/concurrent-ruby/concurrent/utility/engine.rb +56 -0
  135. data/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb +90 -0
  136. data/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb +79 -0
  137. data/lib/concurrent-ruby/concurrent/utility/native_integer.rb +53 -0
  138. data/lib/concurrent-ruby/concurrent/utility/processor_counter.rb +130 -0
  139. data/lib/concurrent-ruby/concurrent/version.rb +3 -0
  140. data/lib/concurrent-ruby/concurrent-ruby.rb +5 -0
  141. data/lib/concurrent-ruby/concurrent.rb +134 -0
  142. metadata +192 -0
@@ -0,0 +1,131 @@
1
+ require 'concurrent/errors'
2
+ require 'concurrent/concern/deprecation'
3
+ require 'concurrent/executor/executor_service'
4
+ require 'concurrent/synchronization'
5
+
6
+ module Concurrent
7
+
8
+ # @!macro abstract_executor_service_public_api
9
+ # @!visibility private
10
+ class AbstractExecutorService < Synchronization::LockableObject
11
+ include ExecutorService
12
+ include Concern::Deprecation
13
+
14
+ # The set of possible fallback policies that may be set at thread pool creation.
15
+ FALLBACK_POLICIES = [:abort, :discard, :caller_runs].freeze
16
+
17
+ # @!macro executor_service_attr_reader_fallback_policy
18
+ attr_reader :fallback_policy
19
+
20
+ attr_reader :name
21
+
22
+ # Create a new thread pool.
23
+ def initialize(opts = {}, &block)
24
+ super(&nil)
25
+ synchronize do
26
+ @auto_terminate = opts.fetch(:auto_terminate, true)
27
+ @name = opts.fetch(:name) if opts.key?(:name)
28
+ ns_initialize(opts, &block)
29
+ end
30
+ end
31
+
32
+ def to_s
33
+ name ? "#{super[0..-2]} name: #{name}>" : super
34
+ end
35
+
36
+ # @!macro executor_service_method_shutdown
37
+ def shutdown
38
+ raise NotImplementedError
39
+ end
40
+
41
+ # @!macro executor_service_method_kill
42
+ def kill
43
+ raise NotImplementedError
44
+ end
45
+
46
+ # @!macro executor_service_method_wait_for_termination
47
+ def wait_for_termination(timeout = nil)
48
+ raise NotImplementedError
49
+ end
50
+
51
+ # @!macro executor_service_method_running_question
52
+ def running?
53
+ synchronize { ns_running? }
54
+ end
55
+
56
+ # @!macro executor_service_method_shuttingdown_question
57
+ def shuttingdown?
58
+ synchronize { ns_shuttingdown? }
59
+ end
60
+
61
+ # @!macro executor_service_method_shutdown_question
62
+ def shutdown?
63
+ synchronize { ns_shutdown? }
64
+ end
65
+
66
+ # @!macro executor_service_method_auto_terminate_question
67
+ def auto_terminate?
68
+ synchronize { @auto_terminate }
69
+ end
70
+
71
+ # @!macro executor_service_method_auto_terminate_setter
72
+ def auto_terminate=(value)
73
+ deprecated "Method #auto_terminate= has no effect. Set :auto_terminate option when executor is initialized."
74
+ end
75
+
76
+ private
77
+
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.
81
+ #
82
+ # @param [Array] args the arguments to the task which is being handled.
83
+ #
84
+ # @!visibility private
85
+ def fallback_action(*args)
86
+ case fallback_policy
87
+ when :abort
88
+ lambda { raise RejectedExecutionError }
89
+ when :discard
90
+ lambda { false }
91
+ when :caller_runs
92
+ lambda {
93
+ begin
94
+ yield(*args)
95
+ rescue => ex
96
+ # let it fail
97
+ log DEBUG, ex
98
+ end
99
+ true
100
+ }
101
+ else
102
+ lambda { fail "Unknown fallback policy #{fallback_policy}" }
103
+ end
104
+ end
105
+
106
+ def ns_execute(*args, &task)
107
+ raise NotImplementedError
108
+ end
109
+
110
+ # @!macro executor_service_method_ns_shutdown_execution
111
+ #
112
+ # Callback method called when an orderly shutdown has completed.
113
+ # The default behavior is to signal all waiting threads.
114
+ def ns_shutdown_execution
115
+ # do nothing
116
+ end
117
+
118
+ # @!macro executor_service_method_ns_kill_execution
119
+ #
120
+ # Callback method called when the executor has been killed.
121
+ # The default behavior is to do nothing.
122
+ def ns_kill_execution
123
+ # do nothing
124
+ end
125
+
126
+ def ns_auto_terminate?
127
+ @auto_terminate
128
+ end
129
+
130
+ end
131
+ end
@@ -0,0 +1,62 @@
1
+ require 'concurrent/utility/engine'
2
+ require 'concurrent/executor/thread_pool_executor'
3
+
4
+ module Concurrent
5
+
6
+ # A thread pool that dynamically grows and shrinks to fit the current workload.
7
+ # New threads are created as needed, existing threads are reused, and threads
8
+ # that remain idle for too long are killed and removed from the pool. These
9
+ # pools are particularly suited to applications that perform a high volume of
10
+ # short-lived tasks.
11
+ #
12
+ # On creation a `CachedThreadPool` has zero running threads. New threads are
13
+ # created on the pool as new operations are `#post`. The size of the pool
14
+ # will grow until `#max_length` threads are in the pool or until the number
15
+ # of threads exceeds the number of running and pending operations. When a new
16
+ # operation is post to the pool the first available idle thread will be tasked
17
+ # with the new operation.
18
+ #
19
+ # Should a thread crash for any reason the thread will immediately be removed
20
+ # from the pool. Similarly, threads which remain idle for an extended period
21
+ # of time will be killed and reclaimed. Thus these thread pools are very
22
+ # efficient at reclaiming unused resources.
23
+ #
24
+ # The API and behavior of this class are based on Java's `CachedThreadPool`
25
+ #
26
+ # @!macro thread_pool_options
27
+ class CachedThreadPool < ThreadPoolExecutor
28
+
29
+ # @!macro cached_thread_pool_method_initialize
30
+ #
31
+ # Create a new thread pool.
32
+ #
33
+ # @param [Hash] opts the options defining pool behavior.
34
+ # @option opts [Symbol] :fallback_policy (`:abort`) the fallback policy
35
+ #
36
+ # @raise [ArgumentError] if `fallback_policy` is not a known policy
37
+ #
38
+ # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newCachedThreadPool--
39
+ def initialize(opts = {})
40
+ defaults = { idletime: DEFAULT_THREAD_IDLETIMEOUT }
41
+ overrides = { min_threads: 0,
42
+ max_threads: DEFAULT_MAX_POOL_SIZE,
43
+ max_queue: DEFAULT_MAX_QUEUE_SIZE }
44
+ super(defaults.merge(opts).merge(overrides))
45
+ end
46
+
47
+ private
48
+
49
+ # @!macro cached_thread_pool_method_initialize
50
+ # @!visibility private
51
+ def ns_initialize(opts)
52
+ super(opts)
53
+ if Concurrent.on_jruby?
54
+ @max_queue = 0
55
+ @executor = java.util.concurrent.Executors.newCachedThreadPool(
56
+ DaemonThreadFactory.new(ns_auto_terminate?))
57
+ @executor.setRejectedExecutionHandler(FALLBACK_POLICY_CLASSES[@fallback_policy].new)
58
+ @executor.setKeepAliveTime(opts.fetch(:idletime, DEFAULT_THREAD_IDLETIMEOUT), java.util.concurrent.TimeUnit::SECONDS)
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,185 @@
1
+ require 'concurrent/concern/logging'
2
+
3
+ module Concurrent
4
+
5
+ ###################################################################
6
+
7
+ # @!macro executor_service_method_post
8
+ #
9
+ # Submit a task to the executor for asynchronous processing.
10
+ #
11
+ # @param [Array] args zero or more arguments to be passed to the task
12
+ #
13
+ # @yield the asynchronous task to perform
14
+ #
15
+ # @return [Boolean] `true` if the task is queued, `false` if the executor
16
+ # is not running
17
+ #
18
+ # @raise [ArgumentError] if no task is given
19
+
20
+ # @!macro executor_service_method_left_shift
21
+ #
22
+ # Submit a task to the executor for asynchronous processing.
23
+ #
24
+ # @param [Proc] task the asynchronous task to perform
25
+ #
26
+ # @return [self] returns itself
27
+
28
+ # @!macro executor_service_method_can_overflow_question
29
+ #
30
+ # Does the task queue have a maximum size?
31
+ #
32
+ # @return [Boolean] True if the task queue has a maximum size else false.
33
+
34
+ # @!macro executor_service_method_serialized_question
35
+ #
36
+ # Does this executor guarantee serialization of its operations?
37
+ #
38
+ # @return [Boolean] True if the executor guarantees that all operations
39
+ # will be post in the order they are received and no two operations may
40
+ # occur simultaneously. Else false.
41
+
42
+ ###################################################################
43
+
44
+ # @!macro executor_service_public_api
45
+ #
46
+ # @!method post(*args, &task)
47
+ # @!macro executor_service_method_post
48
+ #
49
+ # @!method <<(task)
50
+ # @!macro executor_service_method_left_shift
51
+ #
52
+ # @!method can_overflow?
53
+ # @!macro executor_service_method_can_overflow_question
54
+ #
55
+ # @!method serialized?
56
+ # @!macro executor_service_method_serialized_question
57
+
58
+ ###################################################################
59
+
60
+ # @!macro executor_service_attr_reader_fallback_policy
61
+ # @return [Symbol] The fallback policy in effect. Either `:abort`, `:discard`, or `:caller_runs`.
62
+
63
+ # @!macro executor_service_method_shutdown
64
+ #
65
+ # Begin an orderly shutdown. Tasks already in the queue will be executed,
66
+ # but no new tasks will be accepted. Has no additional effect if the
67
+ # thread pool is not running.
68
+
69
+ # @!macro executor_service_method_kill
70
+ #
71
+ # Begin an immediate shutdown. In-progress tasks will be allowed to
72
+ # complete but enqueued tasks will be dismissed and no new tasks
73
+ # will be accepted. Has no additional effect if the thread pool is
74
+ # not running.
75
+
76
+ # @!macro executor_service_method_wait_for_termination
77
+ #
78
+ # Block until executor shutdown is complete or until `timeout` seconds have
79
+ # passed.
80
+ #
81
+ # @note Does not initiate shutdown or termination. Either `shutdown` or `kill`
82
+ # must be called before this method (or on another thread).
83
+ #
84
+ # @param [Integer] timeout the maximum number of seconds to wait for shutdown to complete
85
+ #
86
+ # @return [Boolean] `true` if shutdown complete or false on `timeout`
87
+
88
+ # @!macro executor_service_method_running_question
89
+ #
90
+ # Is the executor running?
91
+ #
92
+ # @return [Boolean] `true` when running, `false` when shutting down or shutdown
93
+
94
+ # @!macro executor_service_method_shuttingdown_question
95
+ #
96
+ # Is the executor shuttingdown?
97
+ #
98
+ # @return [Boolean] `true` when not running and not shutdown, else `false`
99
+
100
+ # @!macro executor_service_method_shutdown_question
101
+ #
102
+ # Is the executor shutdown?
103
+ #
104
+ # @return [Boolean] `true` when shutdown, `false` when shutting down or running
105
+
106
+ # @!macro executor_service_method_auto_terminate_question
107
+ #
108
+ # Is the executor auto-terminate when the application exits?
109
+ #
110
+ # @return [Boolean] `true` when auto-termination is enabled else `false`.
111
+
112
+ # @!macro executor_service_method_auto_terminate_setter
113
+ #
114
+ #
115
+ # Set the auto-terminate behavior for this executor.
116
+ # @deprecated Has no effect
117
+ # @param [Boolean] value The new auto-terminate value to set for this executor.
118
+ # @return [Boolean] `true` when auto-termination is enabled else `false`.
119
+
120
+ ###################################################################
121
+
122
+ # @!macro abstract_executor_service_public_api
123
+ #
124
+ # @!macro executor_service_public_api
125
+ #
126
+ # @!attribute [r] fallback_policy
127
+ # @!macro executor_service_attr_reader_fallback_policy
128
+ #
129
+ # @!method shutdown
130
+ # @!macro executor_service_method_shutdown
131
+ #
132
+ # @!method kill
133
+ # @!macro executor_service_method_kill
134
+ #
135
+ # @!method wait_for_termination(timeout = nil)
136
+ # @!macro executor_service_method_wait_for_termination
137
+ #
138
+ # @!method running?
139
+ # @!macro executor_service_method_running_question
140
+ #
141
+ # @!method shuttingdown?
142
+ # @!macro executor_service_method_shuttingdown_question
143
+ #
144
+ # @!method shutdown?
145
+ # @!macro executor_service_method_shutdown_question
146
+ #
147
+ # @!method auto_terminate?
148
+ # @!macro executor_service_method_auto_terminate_question
149
+ #
150
+ # @!method auto_terminate=(value)
151
+ # @!macro executor_service_method_auto_terminate_setter
152
+
153
+ ###################################################################
154
+
155
+ # @!macro executor_service_public_api
156
+ # @!visibility private
157
+ module ExecutorService
158
+ include Concern::Logging
159
+
160
+ # @!macro executor_service_method_post
161
+ def post(*args, &task)
162
+ raise NotImplementedError
163
+ end
164
+
165
+ # @!macro executor_service_method_left_shift
166
+ def <<(task)
167
+ post(&task)
168
+ self
169
+ end
170
+
171
+ # @!macro executor_service_method_can_overflow_question
172
+ #
173
+ # @note Always returns `false`
174
+ def can_overflow?
175
+ false
176
+ end
177
+
178
+ # @!macro executor_service_method_serialized_question
179
+ #
180
+ # @note Always returns `false`
181
+ def serialized?
182
+ false
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,220 @@
1
+ require 'concurrent/utility/engine'
2
+ require 'concurrent/executor/thread_pool_executor'
3
+
4
+ module Concurrent
5
+
6
+ # @!macro thread_pool_executor_constant_default_max_pool_size
7
+ # Default maximum number of threads that will be created in the pool.
8
+
9
+ # @!macro thread_pool_executor_constant_default_min_pool_size
10
+ # Default minimum number of threads that will be retained in the pool.
11
+
12
+ # @!macro thread_pool_executor_constant_default_max_queue_size
13
+ # Default maximum number of tasks that may be added to the task queue.
14
+
15
+ # @!macro thread_pool_executor_constant_default_thread_timeout
16
+ # Default maximum number of seconds a thread in the pool may remain idle
17
+ # before being reclaimed.
18
+
19
+ # @!macro thread_pool_executor_constant_default_synchronous
20
+ # Default value of the :synchronous option.
21
+
22
+ # @!macro thread_pool_executor_attr_reader_max_length
23
+ # The maximum number of threads that may be created in the pool.
24
+ # @return [Integer] The maximum number of threads that may be created in the pool.
25
+
26
+ # @!macro thread_pool_executor_attr_reader_min_length
27
+ # The minimum number of threads that may be retained in the pool.
28
+ # @return [Integer] The minimum number of threads that may be retained in the pool.
29
+
30
+ # @!macro thread_pool_executor_attr_reader_largest_length
31
+ # The largest number of threads that have been created in the pool since construction.
32
+ # @return [Integer] The largest number of threads that have been created in the pool since construction.
33
+
34
+ # @!macro thread_pool_executor_attr_reader_scheduled_task_count
35
+ # The number of tasks that have been scheduled for execution on the pool since construction.
36
+ # @return [Integer] The number of tasks that have been scheduled for execution on the pool since construction.
37
+
38
+ # @!macro thread_pool_executor_attr_reader_completed_task_count
39
+ # The number of tasks that have been completed by the pool since construction.
40
+ # @return [Integer] The number of tasks that have been completed by the pool since construction.
41
+
42
+ # @!macro thread_pool_executor_attr_reader_idletime
43
+ # The number of seconds that a thread may be idle before being reclaimed.
44
+ # @return [Integer] The number of seconds that a thread may be idle before being reclaimed.
45
+
46
+ # @!macro thread_pool_executor_attr_reader_synchronous
47
+ # Whether or not a value of 0 for :max_queue option means the queue must perform direct hand-off or rather unbounded queue.
48
+ # @return [true, false]
49
+
50
+ # @!macro thread_pool_executor_attr_reader_max_queue
51
+ # The maximum number of tasks that may be waiting in the work queue at any one time.
52
+ # When the queue size reaches `max_queue` subsequent tasks will be rejected in
53
+ # accordance with the configured `fallback_policy`.
54
+ #
55
+ # @return [Integer] The maximum number of tasks that may be waiting in the work queue at any one time.
56
+ # When the queue size reaches `max_queue` subsequent tasks will be rejected in
57
+ # accordance with the configured `fallback_policy`.
58
+
59
+ # @!macro thread_pool_executor_attr_reader_length
60
+ # The number of threads currently in the pool.
61
+ # @return [Integer] The number of threads currently in the pool.
62
+
63
+ # @!macro thread_pool_executor_attr_reader_queue_length
64
+ # The number of tasks in the queue awaiting execution.
65
+ # @return [Integer] The number of tasks in the queue awaiting execution.
66
+
67
+ # @!macro thread_pool_executor_attr_reader_remaining_capacity
68
+ # Number of tasks that may be enqueued before reaching `max_queue` and rejecting
69
+ # new tasks. A value of -1 indicates that the queue may grow without bound.
70
+ #
71
+ # @return [Integer] Number of tasks that may be enqueued before reaching `max_queue` and rejecting
72
+ # new tasks. A value of -1 indicates that the queue may grow without bound.
73
+
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)
84
+
85
+ # @!macro thread_pool_executor_public_api
86
+ #
87
+ # @!macro abstract_executor_service_public_api
88
+ #
89
+ # @!attribute [r] max_length
90
+ # @!macro thread_pool_executor_attr_reader_max_length
91
+ #
92
+ # @!attribute [r] min_length
93
+ # @!macro thread_pool_executor_attr_reader_min_length
94
+ #
95
+ # @!attribute [r] largest_length
96
+ # @!macro thread_pool_executor_attr_reader_largest_length
97
+ #
98
+ # @!attribute [r] scheduled_task_count
99
+ # @!macro thread_pool_executor_attr_reader_scheduled_task_count
100
+ #
101
+ # @!attribute [r] completed_task_count
102
+ # @!macro thread_pool_executor_attr_reader_completed_task_count
103
+ #
104
+ # @!attribute [r] idletime
105
+ # @!macro thread_pool_executor_attr_reader_idletime
106
+ #
107
+ # @!attribute [r] max_queue
108
+ # @!macro thread_pool_executor_attr_reader_max_queue
109
+ #
110
+ # @!attribute [r] length
111
+ # @!macro thread_pool_executor_attr_reader_length
112
+ #
113
+ # @!attribute [r] queue_length
114
+ # @!macro thread_pool_executor_attr_reader_queue_length
115
+ #
116
+ # @!attribute [r] remaining_capacity
117
+ # @!macro thread_pool_executor_attr_reader_remaining_capacity
118
+ #
119
+ # @!method can_overflow?
120
+ # @!macro executor_service_method_can_overflow_question
121
+ #
122
+ # @!method prune_pool
123
+ # @!macro thread_pool_executor_method_prune_pool
124
+
125
+
126
+
127
+
128
+ # @!macro thread_pool_options
129
+ #
130
+ # **Thread Pool Options**
131
+ #
132
+ # Thread pools support several configuration options:
133
+ #
134
+ # * `idletime`: The number of seconds that a thread may be idle before being reclaimed.
135
+ # * `name`: The name of the executor (optional). Printed in the executor's `#to_s` output and
136
+ # a `<name>-worker-<id>` name is given to its threads if supported by used Ruby
137
+ # implementation. `<id>` is uniq for each thread.
138
+ # * `max_queue`: The maximum number of tasks that may be waiting in the work queue at
139
+ # any one time. When the queue size reaches `max_queue` and no new threads can be created,
140
+ # subsequent tasks will be rejected in accordance with the configured `fallback_policy`.
141
+ # * `auto_terminate`: When true (default), the threads started will be marked as daemon.
142
+ # * `fallback_policy`: The policy defining how rejected tasks are handled.
143
+ #
144
+ # Three fallback policies are supported:
145
+ #
146
+ # * `:abort`: Raise a `RejectedExecutionError` exception and discard the task.
147
+ # * `:discard`: Discard the task and return false.
148
+ # * `:caller_runs`: Execute the task on the calling thread.
149
+ #
150
+ # **Shutting Down Thread Pools**
151
+ #
152
+ # Killing a thread pool while tasks are still being processed, either by calling
153
+ # the `#kill` method or at application exit, will have unpredictable results. There
154
+ # is no way for the thread pool to know what resources are being used by the
155
+ # in-progress tasks. When those tasks are killed the impact on those resources
156
+ # cannot be predicted. The *best* practice is to explicitly shutdown all thread
157
+ # pools using the provided methods:
158
+ #
159
+ # * Call `#shutdown` to initiate an orderly termination of all in-progress tasks
160
+ # * Call `#wait_for_termination` with an appropriate timeout interval an allow
161
+ # the orderly shutdown to complete
162
+ # * Call `#kill` *only when* the thread pool fails to shutdown in the allotted time
163
+ #
164
+ # On some runtime platforms (most notably the JVM) the application will not
165
+ # exit until all thread pools have been shutdown. To prevent applications from
166
+ # "hanging" on exit, all threads can be marked as daemon according to the
167
+ # `:auto_terminate` option.
168
+ #
169
+ # ```ruby
170
+ # pool1 = Concurrent::FixedThreadPool.new(5) # threads will be marked as daemon
171
+ # pool2 = Concurrent::FixedThreadPool.new(5, auto_terminate: false) # mark threads as non-daemon
172
+ # ```
173
+ #
174
+ # @note Failure to properly shutdown a thread pool can lead to unpredictable results.
175
+ # Please read *Shutting Down Thread Pools* for more information.
176
+ #
177
+ # @see http://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html Java Tutorials: Thread Pools
178
+ # @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html Java Executors class
179
+ # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html Java ExecutorService interface
180
+ # @see https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#setDaemon-boolean-
181
+
182
+
183
+
184
+
185
+
186
+ # @!macro fixed_thread_pool
187
+ #
188
+ # A thread pool that reuses a fixed number of threads operating off an unbounded queue.
189
+ # At any point, at most `num_threads` will be active processing tasks. When all threads are busy new
190
+ # tasks `#post` to the thread pool are enqueued until a thread becomes available.
191
+ # Should a thread crash for any reason the thread will immediately be removed
192
+ # from the pool and replaced.
193
+ #
194
+ # The API and behavior of this class are based on Java's `FixedThreadPool`
195
+ #
196
+ # @!macro thread_pool_options
197
+ class FixedThreadPool < ThreadPoolExecutor
198
+
199
+ # @!macro fixed_thread_pool_method_initialize
200
+ #
201
+ # Create a new thread pool.
202
+ #
203
+ # @param [Integer] num_threads the number of threads to allocate
204
+ # @param [Hash] opts the options defining pool behavior.
205
+ # @option opts [Symbol] :fallback_policy (`:abort`) the fallback policy
206
+ #
207
+ # @raise [ArgumentError] if `num_threads` is less than or equal to zero
208
+ # @raise [ArgumentError] if `fallback_policy` is not a known policy
209
+ #
210
+ # @see http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newFixedThreadPool-int-
211
+ def initialize(num_threads, opts = {})
212
+ raise ArgumentError.new('number of threads must be greater than zero') if num_threads.to_i < 1
213
+ defaults = { max_queue: DEFAULT_MAX_QUEUE_SIZE,
214
+ idletime: DEFAULT_THREAD_IDLETIMEOUT }
215
+ overrides = { min_threads: num_threads,
216
+ max_threads: num_threads }
217
+ super(defaults.merge(opts).merge(overrides))
218
+ end
219
+ end
220
+ end
@@ -0,0 +1,66 @@
1
+ require 'concurrent/atomic/event'
2
+ require 'concurrent/executor/abstract_executor_service'
3
+ require 'concurrent/executor/serial_executor_service'
4
+
5
+ module Concurrent
6
+
7
+ # An executor service which runs all operations on the current thread,
8
+ # blocking as necessary. Operations are performed in the order they are
9
+ # received and no two operations can be performed simultaneously.
10
+ #
11
+ # This executor service exists mainly for testing an debugging. When used
12
+ # it immediately runs every `#post` operation on the current thread, blocking
13
+ # that thread until the operation is complete. This can be very beneficial
14
+ # during testing because it makes all operations deterministic.
15
+ #
16
+ # @note Intended for use primarily in testing and debugging.
17
+ class ImmediateExecutor < AbstractExecutorService
18
+ include SerialExecutorService
19
+
20
+ # Creates a new executor
21
+ def initialize
22
+ @stopped = Concurrent::Event.new
23
+ end
24
+
25
+ # @!macro executor_service_method_post
26
+ def post(*args, &task)
27
+ raise ArgumentError.new('no block given') unless block_given?
28
+ return false unless running?
29
+ task.call(*args)
30
+ true
31
+ end
32
+
33
+ # @!macro executor_service_method_left_shift
34
+ def <<(task)
35
+ post(&task)
36
+ self
37
+ end
38
+
39
+ # @!macro executor_service_method_running_question
40
+ def running?
41
+ ! shutdown?
42
+ end
43
+
44
+ # @!macro executor_service_method_shuttingdown_question
45
+ def shuttingdown?
46
+ false
47
+ end
48
+
49
+ # @!macro executor_service_method_shutdown_question
50
+ def shutdown?
51
+ @stopped.set?
52
+ end
53
+
54
+ # @!macro executor_service_method_shutdown
55
+ def shutdown
56
+ @stopped.set
57
+ true
58
+ end
59
+ alias_method :kill, :shutdown
60
+
61
+ # @!macro executor_service_method_wait_for_termination
62
+ def wait_for_termination(timeout = nil)
63
+ @stopped.wait(timeout)
64
+ end
65
+ end
66
+ end