concurrent-ruby 0.9.2 → 1.0.0.pre1

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 (77) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -1
  3. data/README.md +67 -68
  4. data/lib/concurrent.rb +14 -1
  5. data/lib/concurrent/array.rb +38 -0
  6. data/lib/concurrent/async.rb +0 -17
  7. data/lib/concurrent/atomic/abstract_thread_local_var.rb +40 -0
  8. data/lib/concurrent/atomic/atomic_boolean.rb +81 -118
  9. data/lib/concurrent/atomic/atomic_fixnum.rb +98 -162
  10. data/lib/concurrent/atomic/atomic_reference.rb +0 -7
  11. data/lib/concurrent/atomic/count_down_latch.rb +62 -103
  12. data/lib/concurrent/atomic/cyclic_barrier.rb +2 -0
  13. data/lib/concurrent/atomic/java_count_down_latch.rb +39 -0
  14. data/lib/concurrent/atomic/java_thread_local_var.rb +50 -0
  15. data/lib/concurrent/atomic/mutex_atomic_boolean.rb +60 -0
  16. data/lib/concurrent/atomic/mutex_atomic_fixnum.rb +91 -0
  17. data/lib/concurrent/atomic/mutex_count_down_latch.rb +43 -0
  18. data/lib/concurrent/atomic/mutex_semaphore.rb +115 -0
  19. data/lib/concurrent/atomic/ruby_thread_local_var.rb +172 -0
  20. data/lib/concurrent/atomic/semaphore.rb +84 -178
  21. data/lib/concurrent/atomic/thread_local_var.rb +63 -294
  22. data/lib/concurrent/atomic_reference/mutex_atomic.rb +14 -8
  23. data/lib/concurrent/atomics.rb +0 -33
  24. data/lib/concurrent/collection/java_non_concurrent_priority_queue.rb +84 -0
  25. data/lib/concurrent/collection/map/atomic_reference_map_backend.rb +921 -0
  26. data/lib/concurrent/collection/map/mri_map_backend.rb +66 -0
  27. data/lib/concurrent/collection/map/non_concurrent_map_backend.rb +142 -0
  28. data/lib/concurrent/collection/map/synchronized_map_backend.rb +86 -0
  29. data/lib/concurrent/collection/non_concurrent_priority_queue.rb +143 -0
  30. data/lib/concurrent/collection/ruby_non_concurrent_priority_queue.rb +150 -0
  31. data/lib/concurrent/concern/logging.rb +1 -1
  32. data/lib/concurrent/concern/obligation.rb +0 -12
  33. data/lib/concurrent/configuration.rb +18 -148
  34. data/lib/concurrent/delay.rb +5 -4
  35. data/lib/concurrent/exchanger.rb +327 -41
  36. data/lib/concurrent/executor/abstract_executor_service.rb +134 -0
  37. data/lib/concurrent/executor/executor.rb +4 -29
  38. data/lib/concurrent/executor/executor_service.rb +23 -359
  39. data/lib/concurrent/executor/immediate_executor.rb +3 -2
  40. data/lib/concurrent/executor/java_executor_service.rb +100 -0
  41. data/lib/concurrent/executor/java_single_thread_executor.rb +3 -2
  42. data/lib/concurrent/executor/java_thread_pool_executor.rb +3 -4
  43. data/lib/concurrent/executor/ruby_executor_service.rb +72 -0
  44. data/lib/concurrent/executor/ruby_single_thread_executor.rb +7 -5
  45. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +3 -11
  46. data/lib/concurrent/executor/safe_task_executor.rb +1 -1
  47. data/lib/concurrent/executor/serial_executor_service.rb +34 -0
  48. data/lib/concurrent/executor/serialized_execution.rb +8 -31
  49. data/lib/concurrent/executor/serialized_execution_delegator.rb +28 -0
  50. data/lib/concurrent/executor/simple_executor_service.rb +1 -10
  51. data/lib/concurrent/executor/timer_set.rb +4 -8
  52. data/lib/concurrent/executors.rb +13 -2
  53. data/lib/concurrent/future.rb +2 -2
  54. data/lib/concurrent/hash.rb +35 -0
  55. data/lib/concurrent/ivar.rb +9 -14
  56. data/lib/concurrent/map.rb +178 -0
  57. data/lib/concurrent/promise.rb +2 -2
  58. data/lib/concurrent/scheduled_task.rb +9 -69
  59. data/lib/concurrent/thread_safe/synchronized_delegator.rb +50 -0
  60. data/lib/concurrent/thread_safe/util.rb +23 -0
  61. data/lib/concurrent/thread_safe/util/adder.rb +71 -0
  62. data/lib/concurrent/thread_safe/util/array_hash_rbx.rb +28 -0
  63. data/lib/concurrent/thread_safe/util/cheap_lockable.rb +115 -0
  64. data/lib/concurrent/thread_safe/util/power_of_two_tuple.rb +37 -0
  65. data/lib/concurrent/thread_safe/util/striped64.rb +236 -0
  66. data/lib/concurrent/thread_safe/util/volatile.rb +73 -0
  67. data/lib/concurrent/thread_safe/util/xor_shift_random.rb +48 -0
  68. data/lib/concurrent/timer_task.rb +3 -3
  69. data/lib/concurrent/tuple.rb +86 -0
  70. data/lib/concurrent/version.rb +2 -2
  71. metadata +37 -10
  72. data/lib/concurrent/atomic/condition.rb +0 -78
  73. data/lib/concurrent/collection/priority_queue.rb +0 -360
  74. data/lib/concurrent/utilities.rb +0 -5
  75. data/lib/concurrent/utility/timeout.rb +0 -39
  76. data/lib/concurrent/utility/timer.rb +0 -26
  77. data/lib/concurrent_ruby.rb +0 -2
@@ -1,5 +1,6 @@
1
1
  require 'concurrent/atomic/event'
2
- require 'concurrent/executor/executor_service'
2
+ require 'concurrent/executor/abstract_executor_service'
3
+ require 'concurrent/executor/serial_executor_service'
3
4
 
4
5
  module Concurrent
5
6
 
@@ -13,7 +14,7 @@ module Concurrent
13
14
  # during testing because it makes all operations deterministic.
14
15
  #
15
16
  # @note Intended for use primarily in testing and debugging.
16
- class ImmediateExecutor
17
+ class ImmediateExecutor < AbstractExecutorService
17
18
  include SerialExecutorService
18
19
 
19
20
  # Creates a new executor
@@ -0,0 +1,100 @@
1
+ if Concurrent.on_jruby?
2
+
3
+ require 'concurrent/errors'
4
+ require 'concurrent/utility/engine'
5
+ require 'concurrent/executor/abstract_executor_service'
6
+
7
+ module Concurrent
8
+
9
+ # @!macro abstract_executor_service_public_api
10
+ # @!visibility private
11
+ class JavaExecutorService < AbstractExecutorService
12
+ java_import 'java.lang.Runnable'
13
+
14
+ FALLBACK_POLICY_CLASSES = {
15
+ abort: java.util.concurrent.ThreadPoolExecutor::AbortPolicy,
16
+ discard: java.util.concurrent.ThreadPoolExecutor::DiscardPolicy,
17
+ caller_runs: java.util.concurrent.ThreadPoolExecutor::CallerRunsPolicy
18
+ }.freeze
19
+ private_constant :FALLBACK_POLICY_CLASSES
20
+
21
+ def initialize(*args, &block)
22
+ super
23
+ ns_make_executor_runnable
24
+ end
25
+
26
+ def post(*args, &task)
27
+ raise ArgumentError.new('no block given') unless block_given?
28
+ return handle_fallback(*args, &task) unless running?
29
+ @executor.submit_runnable Job.new(args, task)
30
+ true
31
+ rescue Java::JavaUtilConcurrent::RejectedExecutionException
32
+ raise RejectedExecutionError
33
+ end
34
+
35
+ def wait_for_termination(timeout = nil)
36
+ if timeout.nil?
37
+ ok = @executor.awaitTermination(60, java.util.concurrent.TimeUnit::SECONDS) until ok
38
+ true
39
+ else
40
+ @executor.awaitTermination(1000 * timeout, java.util.concurrent.TimeUnit::MILLISECONDS)
41
+ end
42
+ end
43
+
44
+ def shutdown
45
+ synchronize do
46
+ self.ns_auto_terminate = false
47
+ @executor.shutdown
48
+ nil
49
+ end
50
+ end
51
+
52
+ def kill
53
+ synchronize do
54
+ self.ns_auto_terminate = false
55
+ @executor.shutdownNow
56
+ nil
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ def ns_running?
63
+ !(ns_shuttingdown? || ns_shutdown?)
64
+ end
65
+
66
+ def ns_shuttingdown?
67
+ if @executor.respond_to? :isTerminating
68
+ @executor.isTerminating
69
+ else
70
+ false
71
+ end
72
+ end
73
+
74
+ def ns_shutdown?
75
+ @executor.isShutdown || @executor.isTerminated
76
+ end
77
+
78
+ def ns_make_executor_runnable
79
+ if !defined?(@executor.submit_runnable)
80
+ @executor.class.class_eval do
81
+ java_alias :submit_runnable, :submit, [java.lang.Runnable.java_class]
82
+ end
83
+ end
84
+ end
85
+
86
+ class Job
87
+ include Runnable
88
+ def initialize(args, block)
89
+ @args = args
90
+ @block = block
91
+ end
92
+
93
+ def run
94
+ @block.call(*@args)
95
+ end
96
+ end
97
+ private_constant :Job
98
+ end
99
+ end
100
+ end
@@ -1,6 +1,7 @@
1
1
  if Concurrent.on_jruby?
2
2
 
3
- require 'concurrent/executor/executor_service'
3
+ require 'concurrent/executor/java_executor_service'
4
+ require 'concurrent/executor/serial_executor_service'
4
5
 
5
6
  module Concurrent
6
7
 
@@ -16,7 +17,7 @@ if Concurrent.on_jruby?
16
17
  super(opts)
17
18
  end
18
19
 
19
- protected
20
+ private
20
21
 
21
22
  def ns_initialize(opts)
22
23
  @executor = java.util.concurrent.Executors.newSingleThreadExecutor
@@ -1,6 +1,6 @@
1
1
  if Concurrent.on_jruby?
2
2
 
3
- require 'concurrent/executor/executor_service'
3
+ require 'concurrent/executor/java_executor_service'
4
4
 
5
5
  module Concurrent
6
6
 
@@ -87,15 +87,14 @@ if Concurrent.on_jruby?
87
87
  super && !@executor.isTerminating
88
88
  end
89
89
 
90
- protected
90
+ private
91
91
 
92
92
  def ns_initialize(opts)
93
93
  min_length = opts.fetch(:min_threads, DEFAULT_MIN_POOL_SIZE).to_i
94
94
  max_length = opts.fetch(:max_threads, DEFAULT_MAX_POOL_SIZE).to_i
95
95
  idletime = opts.fetch(:idletime, DEFAULT_THREAD_IDLETIMEOUT).to_i
96
96
  @max_queue = opts.fetch(:max_queue, DEFAULT_MAX_QUEUE_SIZE).to_i
97
- @fallback_policy = opts.fetch(:fallback_policy, opts.fetch(:overflow_policy, :abort))
98
- deprecated ' :overflow_policy is deprecated terminology, please use :fallback_policy instead' if opts.has_key?(:overflow_policy)
97
+ @fallback_policy = opts.fetch(:fallback_policy, :abort)
99
98
 
100
99
  raise ArgumentError.new("`max_threads` cannot be less than #{DEFAULT_MIN_POOL_SIZE}") if max_length < DEFAULT_MIN_POOL_SIZE
101
100
  raise ArgumentError.new("`max_threads` cannot be greater than #{DEFAULT_MAX_POOL_SIZE}") if max_length > DEFAULT_MAX_POOL_SIZE
@@ -0,0 +1,72 @@
1
+ require 'concurrent/executor/abstract_executor_service'
2
+ require 'concurrent/atomic/event'
3
+
4
+ module Concurrent
5
+
6
+ # @!macro abstract_executor_service_public_api
7
+ # @!visibility private
8
+ class RubyExecutorService < AbstractExecutorService
9
+
10
+ def initialize(*args, &block)
11
+ super
12
+ @stop_event = Event.new
13
+ @stopped_event = Event.new
14
+ ensure_ivar_visibility!
15
+ end
16
+
17
+ def post(*args, &task)
18
+ raise ArgumentError.new('no block given') unless block_given?
19
+ synchronize do
20
+ # If the executor is shut down, reject this task
21
+ return handle_fallback(*args, &task) unless running?
22
+ ns_execute(*args, &task)
23
+ true
24
+ end
25
+ end
26
+
27
+ def shutdown
28
+ synchronize do
29
+ break unless running?
30
+ self.ns_auto_terminate = false
31
+ stop_event.set
32
+ ns_shutdown_execution
33
+ end
34
+ true
35
+ end
36
+
37
+ def kill
38
+ synchronize do
39
+ break if shutdown?
40
+ self.ns_auto_terminate = false
41
+ stop_event.set
42
+ ns_kill_execution
43
+ stopped_event.set
44
+ end
45
+ true
46
+ end
47
+
48
+ def wait_for_termination(timeout = nil)
49
+ stopped_event.wait(timeout)
50
+ end
51
+
52
+ private
53
+
54
+ attr_reader :stop_event, :stopped_event
55
+
56
+ def ns_shutdown_execution
57
+ stopped_event.set
58
+ end
59
+
60
+ def ns_running?
61
+ !stop_event.set?
62
+ end
63
+
64
+ def ns_shuttingdown?
65
+ !(ns_running? || ns_shutdown?)
66
+ end
67
+
68
+ def ns_shutdown?
69
+ stopped_event.set?
70
+ end
71
+ end
72
+ end
@@ -1,4 +1,6 @@
1
- require 'concurrent/executor/executor_service'
1
+ require 'thread'
2
+ require 'concurrent/executor/ruby_executor_service'
3
+ require 'concurrent/executor/serial_executor_service'
2
4
 
3
5
  module Concurrent
4
6
 
@@ -14,7 +16,7 @@ module Concurrent
14
16
  super
15
17
  end
16
18
 
17
- protected
19
+ private
18
20
 
19
21
  def ns_initialize(opts)
20
22
  @queue = Queue.new
@@ -25,19 +27,19 @@ module Concurrent
25
27
  end
26
28
 
27
29
  # @!visibility private
28
- def execute(*args, &task)
30
+ def ns_execute(*args, &task)
29
31
  supervise
30
32
  @queue << [args, task]
31
33
  end
32
34
 
33
35
  # @!visibility private
34
- def shutdown_execution
36
+ def ns_shutdown_execution
35
37
  @queue << :stop
36
38
  stopped_event.set unless alive?
37
39
  end
38
40
 
39
41
  # @!visibility private
40
- def kill_execution
42
+ def ns_kill_execution
41
43
  @queue.clear
42
44
  @thread.kill if alive?
43
45
  end
@@ -1,8 +1,7 @@
1
1
  require 'thread'
2
-
3
2
  require 'concurrent/atomic/event'
4
3
  require 'concurrent/concern/logging'
5
- require 'concurrent/executor/executor_service'
4
+ require 'concurrent/executor/ruby_executor_service'
6
5
  require 'concurrent/utility/monotonic_time'
7
6
 
8
7
  module Concurrent
@@ -96,7 +95,7 @@ module Concurrent
96
95
  synchronize { ns_worker_died worker }
97
96
  end
98
97
 
99
- protected
98
+ private
100
99
 
101
100
  # @!visibility private
102
101
  def ns_initialize(opts)
@@ -104,9 +103,8 @@ module Concurrent
104
103
  @max_length = opts.fetch(:max_threads, DEFAULT_MAX_POOL_SIZE).to_i
105
104
  @idletime = opts.fetch(:idletime, DEFAULT_THREAD_IDLETIMEOUT).to_i
106
105
  @max_queue = opts.fetch(:max_queue, DEFAULT_MAX_QUEUE_SIZE).to_i
107
- @fallback_policy = opts.fetch(:fallback_policy, opts.fetch(:overflow_policy, :abort))
106
+ @fallback_policy = opts.fetch(:fallback_policy, :abort)
108
107
  raise ArgumentError.new("#{@fallback_policy} is not a valid fallback policy") unless FALLBACK_POLICIES.include?(@fallback_policy)
109
- deprecated ':overflow_policy is deprecated terminology, please use :fallback_policy instead' if opts.has_key?(:overflow_policy)
110
108
 
111
109
  raise ArgumentError.new("`max_threads` cannot be less than #{DEFAULT_MIN_POOL_SIZE}") if @max_length < DEFAULT_MIN_POOL_SIZE
112
110
  raise ArgumentError.new("`max_threads` cannot be greater than #{DEFAULT_MAX_POOL_SIZE}") if @max_length > DEFAULT_MAX_POOL_SIZE
@@ -144,8 +142,6 @@ module Concurrent
144
142
  # raise unless @ready.empty? || @queue.empty? # assert
145
143
  end
146
144
 
147
- alias_method :execute, :ns_execute
148
-
149
145
  # @!visibility private
150
146
  def ns_shutdown_execution
151
147
  if @pool.empty?
@@ -160,8 +156,6 @@ module Concurrent
160
156
  # raise unless @ready.empty? || @queue.empty? # assert
161
157
  end
162
158
 
163
- alias_method :shutdown_execution, :ns_shutdown_execution
164
-
165
159
  # @!visibility private
166
160
  def ns_kill_execution
167
161
  # TODO log out unprocessed tasks in queue
@@ -171,8 +165,6 @@ module Concurrent
171
165
  @ready.clear
172
166
  end
173
167
 
174
- alias_method :kill_execution, :ns_kill_execution
175
-
176
168
  # tries to assign task to a worker, tries to get one from @ready or to create new one
177
169
  # @return [true, false] if task is assigned to a worker
178
170
  #
@@ -1,4 +1,4 @@
1
- require 'concurrent/synchronization'
1
+ require 'concurrent/synchronization/object'
2
2
 
3
3
  module Concurrent
4
4
 
@@ -0,0 +1,34 @@
1
+ require 'concurrent/executor/executor_service'
2
+
3
+ module Concurrent
4
+
5
+ # Indicates that the including `ExecutorService` guarantees
6
+ # that all operations will occur in the order they are post and that no
7
+ # two operations may occur simultaneously. This module provides no
8
+ # functionality and provides no guarantees. That is the responsibility
9
+ # of the including class. This module exists solely to allow the including
10
+ # object to be interrogated for its serialization status.
11
+ #
12
+ # @example
13
+ # class Foo
14
+ # include Concurrent::SerialExecutor
15
+ # end
16
+ #
17
+ # foo = Foo.new
18
+ #
19
+ # foo.is_a? Concurrent::ExecutorService #=> true
20
+ # foo.is_a? Concurrent::SerialExecutor #=> true
21
+ # foo.serialized? #=> true
22
+ #
23
+ # @!visibility private
24
+ module SerialExecutorService
25
+ include ExecutorService
26
+
27
+ # @!macro executor_service_method_serialized_question
28
+ #
29
+ # @note Always returns `true`
30
+ def serialized?
31
+ true
32
+ end
33
+ end
34
+ end
@@ -1,7 +1,6 @@
1
- require 'delegate'
2
- require 'concurrent/executor/executor_service'
1
+ require 'concurrent/errors'
3
2
  require 'concurrent/concern/logging'
4
- require 'concurrent/synchronization'
3
+ require 'concurrent/synchronization/object'
5
4
 
6
5
  module Concurrent
7
6
 
@@ -66,7 +65,7 @@ module Concurrent
66
65
  true
67
66
  end
68
67
 
69
- protected
68
+ private
70
69
 
71
70
  def ns_initialize
72
71
  @being_executed = false
@@ -75,11 +74,11 @@ module Concurrent
75
74
 
76
75
  def call_job(job)
77
76
  did_it_run = begin
78
- job.executor.post { work(job) }
79
- true
80
- rescue RejectedExecutionError => ex
81
- false
82
- end
77
+ job.executor.post { work(job) }
78
+ true
79
+ rescue RejectedExecutionError => ex
80
+ false
81
+ end
83
82
 
84
83
  # TODO not the best idea to run it myself
85
84
  unless did_it_run
@@ -105,26 +104,4 @@ module Concurrent
105
104
  call_job job if job
106
105
  end
107
106
  end
108
-
109
- # A wrapper/delegator for any `ExecutorService` that
110
- # guarantees serialized execution of tasks.
111
- #
112
- # @see [SimpleDelegator](http://www.ruby-doc.org/stdlib-2.1.2/libdoc/delegate/rdoc/SimpleDelegator.html)
113
- # @see Concurrent::SerializedExecution
114
- class SerializedExecutionDelegator < SimpleDelegator
115
- include SerialExecutorService
116
-
117
- def initialize(executor)
118
- @executor = executor
119
- @serializer = SerializedExecution.new
120
- super(executor)
121
- end
122
-
123
- # @!macro executor_service_method_post
124
- def post(*args, &task)
125
- Kernel.raise ArgumentError.new('no block given') unless block_given?
126
- return false unless running?
127
- @serializer.post(@executor, *args, &task)
128
- end
129
- end
130
107
  end
@@ -0,0 +1,28 @@
1
+ require 'delegate'
2
+ require 'concurrent/executor/serial_executor_service'
3
+ require 'concurrent/executor/serialized_execution'
4
+
5
+ module Concurrent
6
+
7
+ # A wrapper/delegator for any `ExecutorService` that
8
+ # guarantees serialized execution of tasks.
9
+ #
10
+ # @see [SimpleDelegator](http://www.ruby-doc.org/stdlib-2.1.2/libdoc/delegate/rdoc/SimpleDelegator.html)
11
+ # @see Concurrent::SerializedExecution
12
+ class SerializedExecutionDelegator < SimpleDelegator
13
+ include SerialExecutorService
14
+
15
+ def initialize(executor)
16
+ @executor = executor
17
+ @serializer = SerializedExecution.new
18
+ super(executor)
19
+ end
20
+
21
+ # @!macro executor_service_method_post
22
+ def post(*args, &task)
23
+ raise ArgumentError.new('no block given') unless block_given?
24
+ return false unless running?
25
+ @serializer.post(@executor, *args, &task)
26
+ end
27
+ end
28
+ end