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
@@ -0,0 +1,134 @@
1
+ require 'concurrent/errors'
2
+ require 'concurrent/executor/executor_service'
3
+ require 'concurrent/synchronization/object'
4
+ require 'concurrent/utility/at_exit'
5
+
6
+ module Concurrent
7
+
8
+ # @!macro abstract_executor_service_public_api
9
+ # @!visibility private
10
+ class AbstractExecutorService < Synchronization::Object
11
+ include ExecutorService
12
+
13
+ # The set of possible fallback policies that may be set at thread pool creation.
14
+ FALLBACK_POLICIES = [:abort, :discard, :caller_runs].freeze
15
+
16
+ # @!macro executor_service_attr_reader_fallback_policy
17
+ attr_reader :fallback_policy
18
+
19
+ # Create a new thread pool.
20
+ def initialize(*args, &block)
21
+ super(&nil)
22
+ synchronize { ns_initialize(*args, &block) }
23
+ end
24
+
25
+ # @!macro executor_service_method_shutdown
26
+ def shutdown
27
+ raise NotImplementedError
28
+ end
29
+
30
+ # @!macro executor_service_method_kill
31
+ def kill
32
+ raise NotImplementedError
33
+ end
34
+
35
+ # @!macro executor_service_method_wait_for_termination
36
+ def wait_for_termination(timeout = nil)
37
+ raise NotImplementedError
38
+ end
39
+
40
+ # @!macro executor_service_method_running_question
41
+ def running?
42
+ synchronize { ns_running? }
43
+ end
44
+
45
+ # @!macro executor_service_method_shuttingdown_question
46
+ def shuttingdown?
47
+ synchronize { ns_shuttingdown? }
48
+ end
49
+
50
+ # @!macro executor_service_method_shutdown_question
51
+ def shutdown?
52
+ synchronize { ns_shutdown? }
53
+ end
54
+
55
+ # @!macro executor_service_method_auto_terminate_question
56
+ def auto_terminate?
57
+ synchronize { ns_auto_terminate? }
58
+ end
59
+
60
+ # @!macro executor_service_method_auto_terminate_setter
61
+ def auto_terminate=(value)
62
+ synchronize { self.ns_auto_terminate = value }
63
+ end
64
+
65
+ private
66
+
67
+ # Handler which executes the `fallback_policy` once the queue size
68
+ # reaches `max_queue`.
69
+ #
70
+ # @param [Array] args the arguments to the task which is being handled.
71
+ #
72
+ # @!visibility private
73
+ def handle_fallback(*args)
74
+ case fallback_policy
75
+ when :abort
76
+ raise RejectedExecutionError
77
+ when :discard
78
+ false
79
+ when :caller_runs
80
+ begin
81
+ yield(*args)
82
+ rescue => ex
83
+ # let it fail
84
+ log DEBUG, ex
85
+ end
86
+ true
87
+ else
88
+ fail "Unknown fallback policy #{fallback_policy}"
89
+ end
90
+ end
91
+
92
+ def ns_execute(*args, &task)
93
+ raise NotImplementedError
94
+ end
95
+
96
+ # @!macro [attach] executor_service_method_ns_shutdown_execution
97
+ #
98
+ # Callback method called when an orderly shutdown has completed.
99
+ # The default behavior is to signal all waiting threads.
100
+ def ns_shutdown_execution
101
+ # do nothing
102
+ end
103
+
104
+ # @!macro [attach] executor_service_method_ns_kill_execution
105
+ #
106
+ # Callback method called when the executor has been killed.
107
+ # The default behavior is to do nothing.
108
+ def ns_kill_execution
109
+ # do nothing
110
+ end
111
+
112
+ def ns_auto_terminate?
113
+ !!@auto_terminate
114
+ end
115
+
116
+ def ns_auto_terminate=(value)
117
+ case value
118
+ when true
119
+ AtExit.add(self) { terminate_at_exit }
120
+ @auto_terminate = true
121
+ when false
122
+ AtExit.delete(self)
123
+ @auto_terminate = false
124
+ else
125
+ raise ArgumentError
126
+ end
127
+ end
128
+
129
+ def terminate_at_exit
130
+ kill # TODO be gentle first
131
+ wait_for_termination(10)
132
+ end
133
+ end
134
+ end
@@ -1,12 +1,10 @@
1
- require 'concurrent/configuration'
2
- require 'concurrent/concern/deprecation'
3
- require 'concurrent/executor/executor_service'
1
+ # This file has circular require issues. For now we assume all
2
+ # necessary dependencies have been required already.
4
3
 
5
4
  module Concurrent
6
5
 
7
6
  # @!visibility private
8
7
  module Executor
9
- extend Concern::Deprecation
10
8
 
11
9
  # Get the requested `Executor` based on the values set in the options hash.
12
10
  #
@@ -20,25 +18,8 @@ module Concurrent
20
18
  #
21
19
  # @!visibility private
22
20
  def self.executor_from_options(opts = {}) # :nodoc:
23
- case
24
- when opts.key?(:executor)
25
- if opts[:executor].nil?
26
- nil
27
- else
28
- executor(opts[:executor])
29
- end
30
- when opts.key?(:operation) || opts.key?(:task)
31
- if opts[:operation] == true || opts[:task] == false
32
- deprecated 'use `executor: :fast` instead'
33
- return Concurrent.global_fast_executor
34
- end
35
-
36
- if opts[:operation] == false || opts[:task] == true
37
- deprecated 'use `executor: :io` instead'
38
- return Concurrent.global_io_executor
39
- end
40
-
41
- raise ArgumentError.new("executor '#{opts[:executor]}' not recognized")
21
+ if identifier = opts.fetch(:executor, nil)
22
+ executor(identifier)
42
23
  else
43
24
  nil
44
25
  end
@@ -52,12 +33,6 @@ module Concurrent
52
33
  Concurrent.global_io_executor
53
34
  when :immediate
54
35
  Concurrent.global_immediate_executor
55
- when :operation
56
- deprecated 'use `executor: :fast` instead'
57
- Concurrent.global_fast_executor
58
- when :task
59
- deprecated 'use `executor: :io` instead'
60
- Concurrent.global_io_executor
61
36
  when Concurrent::ExecutorService
62
37
  executor_identifier
63
38
  else
@@ -1,12 +1,9 @@
1
- require 'concurrent/errors'
2
- require 'concurrent/concern/deprecation'
3
1
  require 'concurrent/concern/logging'
4
- require 'concurrent/atomic/event'
5
- require 'concurrent/synchronization'
6
- require 'concurrent/utility/at_exit'
7
2
 
8
3
  module Concurrent
9
4
 
5
+ ###################################################################
6
+
10
7
  # @!macro [new] executor_service_method_post
11
8
  #
12
9
  # Submit a task to the executor for asynchronous processing.
@@ -42,9 +39,7 @@ module Concurrent
42
39
  # will be post in the order they are received and no two operations may
43
40
  # occur simultaneously. Else false.
44
41
 
45
-
46
-
47
-
42
+ ###################################################################
48
43
 
49
44
  # @!macro [new] executor_service_public_api
50
45
  #
@@ -60,75 +55,7 @@ module Concurrent
60
55
  # @!method serialized?
61
56
  # @!macro executor_service_method_serialized_question
62
57
 
63
-
64
-
65
-
66
-
67
- # @!macro executor_service_public_api
68
- # @!visibility private
69
- module ExecutorService
70
- include Concern::Logging
71
- include Concern::Deprecation
72
-
73
- # @!macro executor_service_method_post
74
- def post(*args, &task)
75
- raise NotImplementedError
76
- end
77
-
78
- # @!macro executor_service_method_left_shift
79
- def <<(task)
80
- post(&task)
81
- self
82
- end
83
-
84
- # @!macro executor_service_method_can_overflow_question
85
- #
86
- # @note Always returns `false`
87
- def can_overflow?
88
- false
89
- end
90
-
91
- # @!macro executor_service_method_serialized_question
92
- #
93
- # @note Always returns `false`
94
- def serialized?
95
- false
96
- end
97
- end
98
-
99
- # Indicates that the including `ExecutorService` guarantees
100
- # that all operations will occur in the order they are post and that no
101
- # two operations may occur simultaneously. This module provides no
102
- # functionality and provides no guarantees. That is the responsibility
103
- # of the including class. This module exists solely to allow the including
104
- # object to be interrogated for its serialization status.
105
- #
106
- # @example
107
- # class Foo
108
- # include Concurrent::SerialExecutor
109
- # end
110
- #
111
- # foo = Foo.new
112
- #
113
- # foo.is_a? Concurrent::ExecutorService #=> true
114
- # foo.is_a? Concurrent::SerialExecutor #=> true
115
- # foo.serialized? #=> true
116
- #
117
- # @!visibility private
118
- module SerialExecutorService
119
- include ExecutorService
120
-
121
- # @!macro executor_service_method_serialized_question
122
- #
123
- # @note Always returns `true`
124
- def serialized?
125
- true
126
- end
127
- end
128
-
129
-
130
-
131
-
58
+ ###################################################################
132
59
 
133
60
  # @!macro [new] executor_service_attr_reader_fallback_policy
134
61
  # @return [Symbol] The fallback policy in effect. Either `:abort`, `:discard`, or `:caller_runs`.
@@ -190,9 +117,7 @@ module Concurrent
190
117
  #
191
118
  # @return [Boolean] `true` when auto-termination is enabled else `false`.
192
119
 
193
-
194
-
195
-
120
+ ###################################################################
196
121
 
197
122
  # @!macro [new] abstract_executor_service_public_api
198
123
  #
@@ -225,297 +150,36 @@ module Concurrent
225
150
  # @!method auto_terminate=(value)
226
151
  # @!macro executor_service_method_auto_terminate_setter
227
152
 
153
+ ###################################################################
228
154
 
229
-
230
-
231
-
232
- # @!macro abstract_executor_service_public_api
155
+ # @!macro executor_service_public_api
233
156
  # @!visibility private
234
- class AbstractExecutorService < Synchronization::Object
235
- include ExecutorService
236
-
237
- # The set of possible fallback policies that may be set at thread pool creation.
238
- FALLBACK_POLICIES = [:abort, :discard, :caller_runs].freeze
239
-
240
- # @!macro [attach] executor_service_attr_reader_fallback_policy
241
- attr_reader :fallback_policy
242
-
243
- # Create a new thread pool.
244
- def initialize(*args, &block)
245
- super(&nil)
246
- synchronize { ns_initialize(*args, &block) }
247
- end
248
-
249
- # @!macro [attach] executor_service_method_shutdown
250
- def shutdown
251
- raise NotImplementedError
252
- end
253
-
254
- # @!macro [attach] executor_service_method_kill
255
- def kill
256
- raise NotImplementedError
257
- end
157
+ module ExecutorService
158
+ include Concern::Logging
258
159
 
259
- # @!macro [attach] executor_service_method_wait_for_termination
260
- def wait_for_termination(timeout = nil)
160
+ # @!macro executor_service_method_post
161
+ def post(*args, &task)
261
162
  raise NotImplementedError
262
163
  end
263
164
 
264
- # @!macro [attach] executor_service_method_running_question
265
- def running?
266
- synchronize { ns_running? }
267
- end
268
-
269
- # @!macro [attach] executor_service_method_shuttingdown_question
270
- def shuttingdown?
271
- synchronize { ns_shuttingdown? }
272
- end
273
-
274
- # @!macro [attach] executor_service_method_shutdown_question
275
- def shutdown?
276
- synchronize { ns_shutdown? }
277
- end
278
-
279
- # @!macro [attach] executor_service_method_auto_terminate_question
280
- def auto_terminate?
281
- synchronize { ns_auto_terminate? }
282
- end
283
-
284
- # @!macro [attach] executor_service_method_auto_terminate_setter
285
- def auto_terminate=(value)
286
- synchronize { self.ns_auto_terminate = value }
287
- end
288
-
289
- protected
290
-
291
- # Handler which executes the `fallback_policy` once the queue size
292
- # reaches `max_queue`.
293
- #
294
- # @param [Array] args the arguments to the task which is being handled.
295
- #
296
- # @!visibility private
297
- def handle_fallback(*args)
298
- case fallback_policy
299
- when :abort
300
- raise RejectedExecutionError
301
- when :discard
302
- false
303
- when :caller_runs
304
- begin
305
- yield(*args)
306
- rescue => ex
307
- # let it fail
308
- log DEBUG, ex
309
- end
310
- true
311
- else
312
- fail "Unknown fallback policy #{fallback_policy}"
313
- end
314
- end
315
-
316
- def execute(*args, &task)
317
- raise NotImplementedError
165
+ # @!macro executor_service_method_left_shift
166
+ def <<(task)
167
+ post(&task)
168
+ self
318
169
  end
319
170
 
320
- # @!macro [attach] executor_service_method_shutdown_execution
171
+ # @!macro executor_service_method_can_overflow_question
321
172
  #
322
- # Callback method called when an orderly shutdown has completed.
323
- # The default behavior is to signal all waiting threads.
324
- def shutdown_execution
325
- # do nothing
173
+ # @note Always returns `false`
174
+ def can_overflow?
175
+ false
326
176
  end
327
177
 
328
- # @!macro [attach] executor_service_method_kill_execution
178
+ # @!macro executor_service_method_serialized_question
329
179
  #
330
- # Callback method called when the executor has been killed.
331
- # The default behavior is to do nothing.
332
- def kill_execution
333
- # do nothing
334
- end
335
-
336
- protected
337
-
338
- def ns_auto_terminate?
339
- !!@auto_terminate
340
- end
341
-
342
- def ns_auto_terminate=(value)
343
- case value
344
- when true
345
- AtExit.add(self) { terminate_at_exit }
346
- @auto_terminate = true
347
- when false
348
- AtExit.delete(self)
349
- @auto_terminate = false
350
- else
351
- raise ArgumentError
352
- end
353
- end
354
-
355
- def terminate_at_exit
356
- kill # TODO be gentle first
357
- wait_for_termination(10)
358
- end
359
- end
360
-
361
- # @!macro abstract_executor_service_public_api
362
- # @!visibility private
363
- class RubyExecutorService < AbstractExecutorService
364
-
365
- def initialize(*args, &block)
366
- super
367
- @stop_event = Event.new
368
- @stopped_event = Event.new
369
- ensure_ivar_visibility!
370
- end
371
-
372
- def post(*args, &task)
373
- raise ArgumentError.new('no block given') unless block_given?
374
- synchronize do
375
- # If the executor is shut down, reject this task
376
- return handle_fallback(*args, &task) unless running?
377
- execute(*args, &task)
378
- true
379
- end
380
- end
381
-
382
- def shutdown
383
- synchronize do
384
- break unless running?
385
- self.ns_auto_terminate = false
386
- stop_event.set
387
- shutdown_execution
388
- end
389
- true
390
- end
391
-
392
- def kill
393
- synchronize do
394
- break if shutdown?
395
- self.ns_auto_terminate = false
396
- stop_event.set
397
- kill_execution
398
- stopped_event.set
399
- end
400
- true
401
- end
402
-
403
- def wait_for_termination(timeout = nil)
404
- stopped_event.wait(timeout)
405
- end
406
-
407
- protected
408
-
409
- attr_reader :stop_event, :stopped_event
410
-
411
- def shutdown_execution
412
- stopped_event.set
413
- end
414
-
415
- def ns_running?
416
- !stop_event.set?
417
- end
418
-
419
- def ns_shuttingdown?
420
- !(ns_running? || ns_shutdown?)
421
- end
422
-
423
- def ns_shutdown?
424
- stopped_event.set?
425
- end
426
- end
427
-
428
- if Concurrent.on_jruby?
429
-
430
- # @!macro abstract_executor_service_public_api
431
- # @!visibility private
432
- class JavaExecutorService < AbstractExecutorService
433
- java_import 'java.lang.Runnable'
434
-
435
- FALLBACK_POLICY_CLASSES = {
436
- abort: java.util.concurrent.ThreadPoolExecutor::AbortPolicy,
437
- discard: java.util.concurrent.ThreadPoolExecutor::DiscardPolicy,
438
- caller_runs: java.util.concurrent.ThreadPoolExecutor::CallerRunsPolicy
439
- }.freeze
440
- private_constant :FALLBACK_POLICY_CLASSES
441
-
442
- def initialize(*args, &block)
443
- super
444
- ns_make_executor_runnable
445
- end
446
-
447
- def post(*args, &task)
448
- raise ArgumentError.new('no block given') unless block_given?
449
- return handle_fallback(*args, &task) unless running?
450
- @executor.submit_runnable Job.new(args, task)
451
- true
452
- rescue Java::JavaUtilConcurrent::RejectedExecutionException
453
- raise RejectedExecutionError
454
- end
455
-
456
- def wait_for_termination(timeout = nil)
457
- if timeout.nil?
458
- ok = @executor.awaitTermination(60, java.util.concurrent.TimeUnit::SECONDS) until ok
459
- true
460
- else
461
- @executor.awaitTermination(1000 * timeout, java.util.concurrent.TimeUnit::MILLISECONDS)
462
- end
463
- end
464
-
465
- def shutdown
466
- synchronize do
467
- self.ns_auto_terminate = false
468
- @executor.shutdown
469
- nil
470
- end
471
- end
472
-
473
- def kill
474
- synchronize do
475
- self.ns_auto_terminate = false
476
- @executor.shutdownNow
477
- nil
478
- end
479
- end
480
-
481
- protected
482
-
483
- def ns_running?
484
- !(ns_shuttingdown? || ns_shutdown?)
485
- end
486
-
487
- def ns_shuttingdown?
488
- if @executor.respond_to? :isTerminating
489
- @executor.isTerminating
490
- else
491
- false
492
- end
493
- end
494
-
495
- def ns_shutdown?
496
- @executor.isShutdown || @executor.isTerminated
497
- end
498
-
499
- def ns_make_executor_runnable
500
- if !defined?(@executor.submit_runnable)
501
- @executor.class.class_eval do
502
- java_alias :submit_runnable, :submit, [java.lang.Runnable.java_class]
503
- end
504
- end
505
- end
506
-
507
- class Job
508
- include Runnable
509
- def initialize(args, block)
510
- @args = args
511
- @block = block
512
- end
513
-
514
- def run
515
- @block.call(*@args)
516
- end
517
- end
518
- private_constant :Job
180
+ # @note Always returns `false`
181
+ def serialized?
182
+ false
519
183
  end
520
184
  end
521
185
  end