concurrent-ruby 0.8.0 → 0.9.0.pre2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (144) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +97 -2
  3. data/README.md +103 -54
  4. data/lib/concurrent.rb +34 -14
  5. data/lib/concurrent/async.rb +164 -50
  6. data/lib/concurrent/atom.rb +171 -0
  7. data/lib/concurrent/atomic/atomic_boolean.rb +57 -107
  8. data/lib/concurrent/atomic/atomic_fixnum.rb +73 -101
  9. data/lib/concurrent/atomic/atomic_reference.rb +49 -0
  10. data/lib/concurrent/atomic/condition.rb +23 -12
  11. data/lib/concurrent/atomic/count_down_latch.rb +23 -21
  12. data/lib/concurrent/atomic/cyclic_barrier.rb +47 -47
  13. data/lib/concurrent/atomic/event.rb +33 -42
  14. data/lib/concurrent/atomic/read_write_lock.rb +252 -0
  15. data/lib/concurrent/atomic/semaphore.rb +64 -89
  16. data/lib/concurrent/atomic/thread_local_var.rb +130 -58
  17. data/lib/concurrent/atomic/thread_local_var/weak_key_map.rb +236 -0
  18. data/lib/concurrent/atomic_reference/direct_update.rb +3 -0
  19. data/lib/concurrent/atomic_reference/jruby.rb +6 -3
  20. data/lib/concurrent/atomic_reference/mutex_atomic.rb +10 -32
  21. data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +3 -0
  22. data/lib/concurrent/atomic_reference/rbx.rb +4 -1
  23. data/lib/concurrent/atomic_reference/ruby.rb +6 -3
  24. data/lib/concurrent/atomics.rb +74 -4
  25. data/lib/concurrent/collection/copy_on_notify_observer_set.rb +115 -0
  26. data/lib/concurrent/collection/copy_on_write_observer_set.rb +119 -0
  27. data/lib/concurrent/collection/priority_queue.rb +300 -245
  28. data/lib/concurrent/concern/deprecation.rb +27 -0
  29. data/lib/concurrent/concern/dereferenceable.rb +88 -0
  30. data/lib/concurrent/concern/logging.rb +25 -0
  31. data/lib/concurrent/concern/obligation.rb +228 -0
  32. data/lib/concurrent/concern/observable.rb +85 -0
  33. data/lib/concurrent/configuration.rb +226 -112
  34. data/lib/concurrent/dataflow.rb +2 -3
  35. data/lib/concurrent/delay.rb +141 -50
  36. data/lib/concurrent/edge.rb +30 -0
  37. data/lib/concurrent/errors.rb +10 -0
  38. data/lib/concurrent/exchanger.rb +25 -1
  39. data/lib/concurrent/executor/cached_thread_pool.rb +46 -33
  40. data/lib/concurrent/executor/executor.rb +46 -299
  41. data/lib/concurrent/executor/executor_service.rb +521 -0
  42. data/lib/concurrent/executor/fixed_thread_pool.rb +206 -26
  43. data/lib/concurrent/executor/immediate_executor.rb +9 -9
  44. data/lib/concurrent/executor/indirect_immediate_executor.rb +4 -3
  45. data/lib/concurrent/executor/java_cached_thread_pool.rb +18 -16
  46. data/lib/concurrent/executor/java_fixed_thread_pool.rb +11 -18
  47. data/lib/concurrent/executor/java_single_thread_executor.rb +17 -16
  48. data/lib/concurrent/executor/java_thread_pool_executor.rb +55 -102
  49. data/lib/concurrent/executor/ruby_cached_thread_pool.rb +9 -18
  50. data/lib/concurrent/executor/ruby_fixed_thread_pool.rb +10 -21
  51. data/lib/concurrent/executor/ruby_single_thread_executor.rb +14 -16
  52. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +250 -166
  53. data/lib/concurrent/executor/safe_task_executor.rb +5 -4
  54. data/lib/concurrent/executor/serialized_execution.rb +22 -18
  55. data/lib/concurrent/executor/{per_thread_executor.rb → simple_executor_service.rb} +29 -20
  56. data/lib/concurrent/executor/single_thread_executor.rb +32 -21
  57. data/lib/concurrent/executor/thread_pool_executor.rb +72 -60
  58. data/lib/concurrent/executor/timer_set.rb +96 -84
  59. data/lib/concurrent/executors.rb +1 -1
  60. data/lib/concurrent/future.rb +70 -38
  61. data/lib/concurrent/immutable_struct.rb +89 -0
  62. data/lib/concurrent/ivar.rb +152 -60
  63. data/lib/concurrent/lazy_register.rb +40 -20
  64. data/lib/concurrent/maybe.rb +226 -0
  65. data/lib/concurrent/mutable_struct.rb +227 -0
  66. data/lib/concurrent/mvar.rb +44 -43
  67. data/lib/concurrent/promise.rb +208 -134
  68. data/lib/concurrent/scheduled_task.rb +339 -43
  69. data/lib/concurrent/settable_struct.rb +127 -0
  70. data/lib/concurrent/synchronization.rb +17 -0
  71. data/lib/concurrent/synchronization/abstract_object.rb +163 -0
  72. data/lib/concurrent/synchronization/abstract_struct.rb +158 -0
  73. data/lib/concurrent/synchronization/condition.rb +53 -0
  74. data/lib/concurrent/synchronization/java_object.rb +35 -0
  75. data/lib/concurrent/synchronization/lock.rb +32 -0
  76. data/lib/concurrent/synchronization/monitor_object.rb +24 -0
  77. data/lib/concurrent/synchronization/mutex_object.rb +43 -0
  78. data/lib/concurrent/synchronization/object.rb +78 -0
  79. data/lib/concurrent/synchronization/rbx_object.rb +75 -0
  80. data/lib/concurrent/timer_task.rb +87 -100
  81. data/lib/concurrent/tvar.rb +42 -38
  82. data/lib/concurrent/utilities.rb +3 -1
  83. data/lib/concurrent/utility/at_exit.rb +97 -0
  84. data/lib/concurrent/utility/engine.rb +40 -0
  85. data/lib/concurrent/utility/monotonic_time.rb +59 -0
  86. data/lib/concurrent/utility/native_extension_loader.rb +56 -0
  87. data/lib/concurrent/utility/processor_counter.rb +156 -0
  88. data/lib/concurrent/utility/timeout.rb +18 -14
  89. data/lib/concurrent/utility/timer.rb +11 -6
  90. data/lib/concurrent/version.rb +2 -1
  91. data/lib/concurrent_ruby.rb +1 -0
  92. metadata +47 -83
  93. data/lib/concurrent/actor.rb +0 -103
  94. data/lib/concurrent/actor/behaviour.rb +0 -70
  95. data/lib/concurrent/actor/behaviour/abstract.rb +0 -48
  96. data/lib/concurrent/actor/behaviour/awaits.rb +0 -21
  97. data/lib/concurrent/actor/behaviour/buffer.rb +0 -54
  98. data/lib/concurrent/actor/behaviour/errors_on_unknown_message.rb +0 -12
  99. data/lib/concurrent/actor/behaviour/executes_context.rb +0 -18
  100. data/lib/concurrent/actor/behaviour/linking.rb +0 -45
  101. data/lib/concurrent/actor/behaviour/pausing.rb +0 -77
  102. data/lib/concurrent/actor/behaviour/removes_child.rb +0 -16
  103. data/lib/concurrent/actor/behaviour/sets_results.rb +0 -36
  104. data/lib/concurrent/actor/behaviour/supervised.rb +0 -59
  105. data/lib/concurrent/actor/behaviour/supervising.rb +0 -34
  106. data/lib/concurrent/actor/behaviour/terminates_children.rb +0 -13
  107. data/lib/concurrent/actor/behaviour/termination.rb +0 -54
  108. data/lib/concurrent/actor/context.rb +0 -154
  109. data/lib/concurrent/actor/core.rb +0 -217
  110. data/lib/concurrent/actor/default_dead_letter_handler.rb +0 -9
  111. data/lib/concurrent/actor/envelope.rb +0 -41
  112. data/lib/concurrent/actor/errors.rb +0 -27
  113. data/lib/concurrent/actor/internal_delegations.rb +0 -49
  114. data/lib/concurrent/actor/public_delegations.rb +0 -40
  115. data/lib/concurrent/actor/reference.rb +0 -81
  116. data/lib/concurrent/actor/root.rb +0 -37
  117. data/lib/concurrent/actor/type_check.rb +0 -48
  118. data/lib/concurrent/actor/utils.rb +0 -10
  119. data/lib/concurrent/actor/utils/ad_hoc.rb +0 -21
  120. data/lib/concurrent/actor/utils/balancer.rb +0 -42
  121. data/lib/concurrent/actor/utils/broadcast.rb +0 -52
  122. data/lib/concurrent/actor/utils/pool.rb +0 -59
  123. data/lib/concurrent/actress.rb +0 -3
  124. data/lib/concurrent/agent.rb +0 -209
  125. data/lib/concurrent/atomic.rb +0 -92
  126. data/lib/concurrent/atomic/copy_on_notify_observer_set.rb +0 -118
  127. data/lib/concurrent/atomic/copy_on_write_observer_set.rb +0 -117
  128. data/lib/concurrent/atomic/synchronization.rb +0 -51
  129. data/lib/concurrent/channel/buffered_channel.rb +0 -85
  130. data/lib/concurrent/channel/channel.rb +0 -41
  131. data/lib/concurrent/channel/unbuffered_channel.rb +0 -35
  132. data/lib/concurrent/channel/waitable_list.rb +0 -40
  133. data/lib/concurrent/channels.rb +0 -5
  134. data/lib/concurrent/collection/blocking_ring_buffer.rb +0 -71
  135. data/lib/concurrent/collection/ring_buffer.rb +0 -59
  136. data/lib/concurrent/collections.rb +0 -3
  137. data/lib/concurrent/dereferenceable.rb +0 -108
  138. data/lib/concurrent/executor/ruby_thread_pool_worker.rb +0 -73
  139. data/lib/concurrent/logging.rb +0 -20
  140. data/lib/concurrent/obligation.rb +0 -171
  141. data/lib/concurrent/observable.rb +0 -73
  142. data/lib/concurrent/options_parser.rb +0 -52
  143. data/lib/concurrent/utility/processor_count.rb +0 -152
  144. data/lib/extension_helper.rb +0 -37
@@ -1,27 +0,0 @@
1
- module Concurrent
2
- module Actor
3
- Error = Class.new(StandardError)
4
-
5
- class ActorTerminated < Error
6
- include TypeCheck
7
-
8
- attr_reader :reference
9
-
10
- def initialize(reference)
11
- @reference = Type! reference, Reference
12
- super reference.path
13
- end
14
- end
15
-
16
- class UnknownMessage < Error
17
- include TypeCheck
18
-
19
- attr_reader :envelope
20
-
21
- def initialize(envelope)
22
- @envelope = Type! envelope, Envelope
23
- super envelope.message.inspect
24
- end
25
- end
26
- end
27
- end
@@ -1,49 +0,0 @@
1
- module Concurrent
2
- module Actor
3
- module InternalDelegations
4
- include PublicDelegations
5
-
6
- # @see Core#children
7
- def children
8
- core.children
9
- end
10
-
11
- # @see Core#terminate!
12
- def terminate!
13
- behaviour!(Behaviour::Termination).terminate!
14
- end
15
-
16
- # delegates to core.log
17
- # @see Logging#log
18
- def log(level, message = nil, &block)
19
- core.log(level, message, &block)
20
- end
21
-
22
- # @see AbstractContext#dead_letter_routing
23
- def dead_letter_routing
24
- context.dead_letter_routing
25
- end
26
-
27
- def redirect(reference, envelope = self.envelope)
28
- reference.message(envelope.message, envelope.ivar)
29
- Behaviour::MESSAGE_PROCESSED
30
- end
31
-
32
- # @return [AbstractContext]
33
- def context
34
- core.context
35
- end
36
-
37
- # see Core#behaviour
38
- def behaviour(behaviour_class)
39
- core.behaviour(behaviour_class)
40
- end
41
-
42
- # see Core#behaviour!
43
- def behaviour!(behaviour_class)
44
- core.behaviour!(behaviour_class)
45
- end
46
-
47
- end
48
- end
49
- end
@@ -1,40 +0,0 @@
1
- module Concurrent
2
- module Actor
3
-
4
- # Provides publicly expose-able methods from {Core}.
5
- module PublicDelegations
6
- # @see Core#name
7
- def name
8
- core.name
9
- end
10
-
11
- # @see Core#path
12
- def path
13
- core.path
14
- end
15
-
16
- # @see Core#parent
17
- def parent
18
- core.parent
19
- end
20
-
21
- # @see Core#reference
22
- def reference
23
- core.reference
24
- end
25
-
26
- # @see Core#executor
27
- def executor
28
- core.executor
29
- end
30
-
31
- # @see Core#context_class
32
- def context_class
33
- core.context_class
34
- end
35
-
36
- alias_method :ref, :reference
37
- alias_method :actor_class, :context_class
38
- end
39
- end
40
- end
@@ -1,81 +0,0 @@
1
- module Concurrent
2
- module Actor
3
-
4
- # Reference is public interface of Actor instances. It is used for sending messages and can
5
- # be freely passed around the program. It also provides some basic information about the actor,
6
- # see {PublicDelegations}.
7
- class Reference
8
- include TypeCheck
9
- include PublicDelegations
10
-
11
- attr_reader :core
12
- private :core
13
-
14
- # @!visibility private
15
- def initialize(core)
16
- @core = Type! core, Core
17
- end
18
-
19
- # tells message to the actor, returns immediately
20
- # @param [Object] message
21
- # @return [Reference] self
22
- def tell(message)
23
- message message, nil
24
- end
25
-
26
- alias_method :<<, :tell
27
-
28
- # @note it's a good practice to use tell whenever possible. Ask should be used only for
29
- # testing and when it returns very shortly. It can lead to deadlock if all threads in
30
- # global_task_pool will block on while asking. It's fine to use it form outside of actors and
31
- # global_task_pool.
32
- #
33
- # sends message to the actor and asks for the result of its processing, returns immediately
34
- # @param [Object] message
35
- # @param [Ivar] ivar to be fulfilled be message's processing result
36
- # @return [IVar] supplied ivar
37
- def ask(message, ivar = IVar.new)
38
- message message, ivar
39
- end
40
-
41
- # @note it's a good practice to use tell whenever possible. Ask should be used only for
42
- # testing and when it returns very shortly. It can lead to deadlock if all threads in
43
- # global_task_pool will block on while asking. It's fine to use it form outside of actors and
44
- # global_task_pool.
45
- #
46
- # sends message to the actor and asks for the result of its processing, blocks
47
- # @param [Object] message
48
- # @param [Ivar] ivar to be fulfilled be message's processing result
49
- # @return [Object] message's processing result
50
- # @raise [Exception] ivar.reason if ivar is #rejected?
51
- def ask!(message, ivar = IVar.new)
52
- ask(message, ivar).value!
53
- end
54
-
55
- # behaves as {#tell} when no ivar and as {#ask} when ivar
56
- def message(message, ivar = nil)
57
- core.on_envelope Envelope.new(message, ivar, Actor.current || Thread.current, self)
58
- return ivar || self
59
- end
60
-
61
- # @see AbstractContext#dead_letter_routing
62
- def dead_letter_routing
63
- core.dead_letter_routing
64
- end
65
-
66
- def to_s
67
- "#<#{self.class} #{path} (#{actor_class})>"
68
- end
69
-
70
- alias_method :inspect, :to_s
71
-
72
- def ==(other)
73
- Type? other, self.class and other.send(:core) == core
74
- end
75
-
76
- # to avoid confusion with Kernel.spawn
77
- undef_method :spawn
78
- end
79
-
80
- end
81
- end
@@ -1,37 +0,0 @@
1
- module Concurrent
2
- module Actor
3
- # implements the root actor
4
- class Root < AbstractContext
5
-
6
- def initialize
7
- # noinspection RubyArgCount
8
- @dead_letter_router = Core.new(parent: reference,
9
- class: DefaultDeadLetterHandler,
10
- supervise: true,
11
- name: :default_dead_letter_handler).reference
12
- end
13
-
14
- # to allow spawning of new actors, spawn needs to be called inside the parent Actor
15
- def on_message(message)
16
- case
17
- when message.is_a?(Array) && message.first == :spawn
18
- Actor.spawn message[1], &message[2]
19
- when message == :dead_letter_routing
20
- @dead_letter_router
21
- else
22
- # ignore
23
- end
24
- end
25
-
26
- def dead_letter_routing
27
- @dead_letter_router
28
- end
29
-
30
- def behaviour_definition
31
- [*Behaviour.base,
32
- [Behaviour::Supervising, [:reset!, :one_for_one]],
33
- *Behaviour.user_messages(:just_log)]
34
- end
35
- end
36
- end
37
- end
@@ -1,48 +0,0 @@
1
- module Concurrent
2
- module Actor
3
-
4
- # taken from Algebrick
5
- # supplies type-checking helpers whenever included
6
- module TypeCheck
7
-
8
- def Type?(value, *types)
9
- types.any? { |t| value.is_a? t }
10
- end
11
-
12
- def Type!(value, *types)
13
- Type?(value, *types) or
14
- TypeCheck.error(value, 'is not', types)
15
- value
16
- end
17
-
18
- def Match?(value, *types)
19
- types.any? { |t| t === value }
20
- end
21
-
22
- def Match!(value, *types)
23
- Match?(value, *types) or
24
- TypeCheck.error(value, 'is not matching', types)
25
- value
26
- end
27
-
28
- def Child?(value, *types)
29
- Type?(value, Class) &&
30
- types.any? { |t| value <= t }
31
- end
32
-
33
- def Child!(value, *types)
34
- Child?(value, *types) or
35
- TypeCheck.error(value, 'is not child', types)
36
- value
37
- end
38
-
39
- private
40
-
41
- def self.error(value, message, types)
42
- raise TypeError,
43
- "Value (#{value.class}) '#{value}' #{message} any of: #{types.join('; ')}."
44
- end
45
- end
46
- end
47
- end
48
-
@@ -1,10 +0,0 @@
1
- module Concurrent
2
- module Actor
3
- module Utils
4
- require 'concurrent/actor/utils/ad_hoc'
5
- require 'concurrent/actor/utils/broadcast'
6
- require 'concurrent/actor/utils/balancer'
7
- require 'concurrent/actor/utils/pool'
8
- end
9
- end
10
- end
@@ -1,21 +0,0 @@
1
- module Concurrent
2
- module Actor
3
- module Utils
4
- # Allows quick creation of actors with behaviour defined by blocks.
5
- # @example ping
6
- # AdHoc.spawn :forward, an_actor do |where|
7
- # # this block has to return proc defining #on_message behaviour
8
- # -> message { where.tell message }
9
- # end
10
- class AdHoc < Context
11
- def initialize(*args, &initializer)
12
- @on_message = Type! initializer.call(*args), Proc
13
- end
14
-
15
- def on_message(message)
16
- instance_exec message, &@on_message
17
- end
18
- end
19
- end
20
- end
21
- end
@@ -1,42 +0,0 @@
1
- module Concurrent
2
- module Actor
3
- module Utils
4
-
5
- # Distributes messages between subscribed actors. Each actor'll get only one message then
6
- # it's unsubscribed. The actor needs to resubscribe when it's ready to receive next message.
7
- # It will buffer the messages if there is no worker registered.
8
- # @see Pool
9
- class Balancer < RestartingContext
10
-
11
- def initialize
12
- @receivers = []
13
- @buffer = []
14
- end
15
-
16
- def on_message(message)
17
- case message
18
- when :subscribe
19
- @receivers << envelope.sender
20
- distribute
21
- true
22
- when :unsubscribe
23
- @receivers.delete envelope.sender
24
- true
25
- when :subscribed?
26
- @receivers.include? envelope.sender
27
- else
28
- @buffer << envelope
29
- distribute
30
- Behaviour::MESSAGE_PROCESSED
31
- end
32
- end
33
-
34
- def distribute
35
- while !@receivers.empty? && !@buffer.empty?
36
- redirect @receivers.shift, @buffer.shift
37
- end
38
- end
39
- end
40
- end
41
- end
42
- end
@@ -1,52 +0,0 @@
1
- require 'set'
2
-
3
- module Concurrent
4
- module Actor
5
- module Utils
6
-
7
- # Allows to build pub/sub easily.
8
- # @example news
9
- # news_channel = Concurrent::Actor::Utils::Broadcast.spawn :news
10
- #
11
- # 2.times do |i|
12
- # Concurrent::Actor::Utils::AdHoc.spawn "listener-#{i}" do
13
- # news_channel << :subscribe
14
- # -> message { puts message }
15
- # end
16
- # end
17
- #
18
- # news_channel << 'Ruby rocks!'
19
- # # prints: 'Ruby rocks!' twice
20
- class Broadcast < RestartingContext
21
-
22
- def initialize
23
- @receivers = Set.new
24
- end
25
-
26
- def on_message(message)
27
- case message
28
- when :subscribe
29
- if envelope.sender.is_a? Reference
30
- @receivers.add envelope.sender
31
- true
32
- else
33
- false
34
- end
35
- when :unsubscribe
36
- !!@receivers.delete(envelope.sender)
37
- when :subscribed?
38
- @receivers.include? envelope.sender
39
- else
40
- filtered_receivers.each { |r| r << message }
41
- end
42
- end
43
-
44
- # override to define different behaviour, filtering etc
45
- def filtered_receivers
46
- @receivers
47
- end
48
- end
49
-
50
- end
51
- end
52
- end
@@ -1,59 +0,0 @@
1
- require 'concurrent/actor/utils/balancer'
2
-
3
- module Concurrent
4
- module Actor
5
- module Utils
6
-
7
- # Allows to create a pool of workers and distribute work between them
8
- # @param [Integer] size number of workers
9
- # @yield [balancer, index] a block spawning an worker instance. called +size+ times.
10
- # The worker should be descendant of AbstractWorker and supervised, see example.
11
- # @yieldparam [Balancer] balancer to pass to the worker
12
- # @yieldparam [Integer] index of the worker, usually used in its name
13
- # @yieldreturn [Reference] the reference of newly created worker
14
- # @example
15
- # class Worker < Concurrent::Actor::Utils::AbstractWorker
16
- # def work(message)
17
- # p message * 5
18
- # end
19
- # end
20
- #
21
- # pool = Concurrent::Actor::Utils::Pool.spawn! 'pool', 5 do |balancer, index|
22
- # Worker.spawn name: "worker-#{index}", supervise: true, args: [balancer]
23
- # end
24
- #
25
- # pool << 'asd' << 2
26
- # # prints:
27
- # # "asdasdasdasdasd"
28
- # # 10
29
- class Pool < RestartingContext
30
- def initialize(size, &worker_initializer)
31
- @balancer = Balancer.spawn name: :balancer, supervise: true
32
- @workers = Array.new(size, &worker_initializer.curry[@balancer])
33
- @workers.each { |w| Type! w, Reference }
34
- end
35
-
36
- def on_message(message)
37
- redirect @balancer
38
- end
39
- end
40
-
41
- class AbstractWorker < RestartingContext
42
- def initialize(balancer)
43
- @balancer = balancer
44
- @balancer << :subscribe
45
- end
46
-
47
- def on_message(message)
48
- work message
49
- ensure
50
- @balancer << :subscribe
51
- end
52
-
53
- def work(message)
54
- raise NotImplementedError
55
- end
56
- end
57
- end
58
- end
59
- end