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
@@ -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