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.
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,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