concurrent-ruby 0.9.2 → 1.0.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
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