concurrent-ruby 0.6.1 → 0.7.0.rc0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/concurrent.rb +3 -4
  4. data/lib/concurrent/atomic.rb +46 -0
  5. data/lib/concurrent/atomic_reference/concurrent_update_error.rb +7 -0
  6. data/lib/concurrent/atomic_reference/delegated_update.rb +28 -0
  7. data/lib/concurrent/atomic_reference/direct_update.rb +28 -0
  8. data/lib/concurrent/atomic_reference/jruby.rb +8 -0
  9. data/lib/concurrent/atomic_reference/mutex_atomic.rb +47 -0
  10. data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +24 -0
  11. data/lib/concurrent/atomic_reference/rbx.rb +16 -0
  12. data/lib/concurrent/atomic_reference/ruby.rb +16 -0
  13. data/lib/concurrent/atomics.rb +1 -1
  14. data/lib/concurrent/configuration.rb +1 -1
  15. data/lib/concurrent/supervisor.rb +1 -1
  16. data/lib/concurrent/timer_task.rb +0 -36
  17. data/lib/concurrent/version.rb +1 -1
  18. data/lib/concurrent_ruby_ext.so +0 -0
  19. data/lib/extension_helper.rb +9 -0
  20. metadata +16 -148
  21. data/lib/concurrent/actor/actor.rb +0 -270
  22. data/lib/concurrent/actor/postable.rb +0 -102
  23. data/lib/concurrent/actors.rb +0 -2
  24. data/lib/concurrent/atomic/atomic.rb +0 -48
  25. data/lib/concurrent/runnable.rb +0 -90
  26. data/lib/concurrent/stoppable.rb +0 -20
  27. data/spec/concurrent/actor/actor_spec.rb +0 -376
  28. data/spec/concurrent/actor/postable_shared.rb +0 -218
  29. data/spec/concurrent/actress_spec.rb +0 -211
  30. data/spec/concurrent/agent_spec.rb +0 -500
  31. data/spec/concurrent/async_spec.rb +0 -352
  32. data/spec/concurrent/atomic/atomic_boolean_spec.rb +0 -172
  33. data/spec/concurrent/atomic/atomic_fixnum_spec.rb +0 -186
  34. data/spec/concurrent/atomic/atomic_spec.rb +0 -133
  35. data/spec/concurrent/atomic/condition_spec.rb +0 -171
  36. data/spec/concurrent/atomic/copy_on_notify_observer_set_spec.rb +0 -10
  37. data/spec/concurrent/atomic/copy_on_write_observer_set_spec.rb +0 -10
  38. data/spec/concurrent/atomic/count_down_latch_spec.rb +0 -151
  39. data/spec/concurrent/atomic/cyclic_barrier_spec.rb +0 -248
  40. data/spec/concurrent/atomic/event_spec.rb +0 -200
  41. data/spec/concurrent/atomic/observer_set_shared.rb +0 -242
  42. data/spec/concurrent/atomic/thread_local_var_spec.rb +0 -113
  43. data/spec/concurrent/channel/buffered_channel_spec.rb +0 -151
  44. data/spec/concurrent/channel/channel_spec.rb +0 -39
  45. data/spec/concurrent/channel/probe_spec.rb +0 -77
  46. data/spec/concurrent/channel/unbuffered_channel_spec.rb +0 -132
  47. data/spec/concurrent/collection/blocking_ring_buffer_spec.rb +0 -149
  48. data/spec/concurrent/collection/priority_queue_spec.rb +0 -317
  49. data/spec/concurrent/collection/ring_buffer_spec.rb +0 -126
  50. data/spec/concurrent/configuration_spec.rb +0 -69
  51. data/spec/concurrent/dataflow_spec.rb +0 -242
  52. data/spec/concurrent/delay_spec.rb +0 -91
  53. data/spec/concurrent/dereferenceable_shared.rb +0 -146
  54. data/spec/concurrent/exchanger_spec.rb +0 -66
  55. data/spec/concurrent/executor/cached_thread_pool_shared.rb +0 -115
  56. data/spec/concurrent/executor/fixed_thread_pool_shared.rb +0 -136
  57. data/spec/concurrent/executor/global_thread_pool_shared.rb +0 -35
  58. data/spec/concurrent/executor/immediate_executor_spec.rb +0 -12
  59. data/spec/concurrent/executor/java_cached_thread_pool_spec.rb +0 -44
  60. data/spec/concurrent/executor/java_fixed_thread_pool_spec.rb +0 -64
  61. data/spec/concurrent/executor/java_single_thread_executor_spec.rb +0 -21
  62. data/spec/concurrent/executor/java_thread_pool_executor_spec.rb +0 -71
  63. data/spec/concurrent/executor/per_thread_executor_spec.rb +0 -57
  64. data/spec/concurrent/executor/ruby_cached_thread_pool_spec.rb +0 -69
  65. data/spec/concurrent/executor/ruby_fixed_thread_pool_spec.rb +0 -39
  66. data/spec/concurrent/executor/ruby_single_thread_executor_spec.rb +0 -18
  67. data/spec/concurrent/executor/ruby_thread_pool_executor_spec.rb +0 -171
  68. data/spec/concurrent/executor/safe_task_executor_spec.rb +0 -103
  69. data/spec/concurrent/executor/thread_pool_class_cast_spec.rb +0 -52
  70. data/spec/concurrent/executor/thread_pool_executor_shared.rb +0 -155
  71. data/spec/concurrent/executor/thread_pool_shared.rb +0 -269
  72. data/spec/concurrent/executor/timer_set_spec.rb +0 -183
  73. data/spec/concurrent/future_spec.rb +0 -329
  74. data/spec/concurrent/ivar_spec.rb +0 -215
  75. data/spec/concurrent/mvar_spec.rb +0 -380
  76. data/spec/concurrent/obligation_shared.rb +0 -102
  77. data/spec/concurrent/obligation_spec.rb +0 -282
  78. data/spec/concurrent/observable_shared.rb +0 -177
  79. data/spec/concurrent/observable_spec.rb +0 -56
  80. data/spec/concurrent/options_parser_spec.rb +0 -71
  81. data/spec/concurrent/promise_spec.rb +0 -367
  82. data/spec/concurrent/runnable_shared.rb +0 -68
  83. data/spec/concurrent/runnable_spec.rb +0 -235
  84. data/spec/concurrent/scheduled_task_spec.rb +0 -340
  85. data/spec/concurrent/stoppable_shared.rb +0 -37
  86. data/spec/concurrent/supervisor_spec.rb +0 -1149
  87. data/spec/concurrent/timer_task_spec.rb +0 -256
  88. data/spec/concurrent/tvar_spec.rb +0 -137
  89. data/spec/concurrent/utility/processor_count_spec.rb +0 -20
  90. data/spec/concurrent/utility/timeout_spec.rb +0 -50
  91. data/spec/concurrent/utility/timer_spec.rb +0 -52
  92. data/spec/spec_helper.rb +0 -41
  93. data/spec/support/example_group_extensions.rb +0 -52
  94. data/spec/support/less_than_or_equal_to_matcher.rb +0 -5
@@ -1,270 +0,0 @@
1
- require 'thread'
2
- require 'observer'
3
-
4
- require 'concurrent/actor/postable'
5
- require 'concurrent/atomic/event'
6
- require 'concurrent/obligation'
7
- require 'concurrent/runnable'
8
-
9
- module Concurrent
10
-
11
- # Actor-based concurrency is all the rage in some circles. Originally described in
12
- # 1973, the actor model is a paradigm for creating asynchronous, concurrent objects
13
- # that is becoming increasingly popular. Much has changed since actors were first
14
- # written about four decades ago, which has led to a serious fragmentation within
15
- # the actor community. There is *no* universally accepted, strict definition of
16
- # "actor" and actor implementations differ widely between languages and libraries.
17
- #
18
- # A good definition of "actor" is:
19
- #
20
- # An independent, concurrent, single-purpose, computational entity that communicates exclusively via message passing.
21
- #
22
- # The +Concurrent::Actor+ class in this library is based solely on the
23
- # {http://www.scala-lang.org/api/current/index.html#scala.actors.Actor Actor} trait
24
- # defined in the Scala standard library. It does not implement all the features of
25
- # Scala's +Actor+ but its behavior for what *has* been implemented is nearly identical.
26
- # The excluded features mostly deal with Scala's message semantics, strong typing,
27
- # and other characteristics of Scala that don't really apply to Ruby.
28
- #
29
- # Unlike many of the abstractions in this library, +Actor+ takes an *object-oriented*
30
- # approach to asynchronous concurrency, rather than a *functional programming*
31
- # approach.
32
- #
33
- # Because +Actor+ mixes in the +Concurrent::Runnable+ module subclasses have access to
34
- # the +#on_error+ method and can override it to implement custom error handling. The
35
- # +Actor+ base class does not use +#on_error+ so as to avoid conflit with subclasses
36
- # which override it. Generally speaking, +#on_error+ should not be used. The +Actor+
37
- # base class provides concictent, reliable, and robust error handling already, and
38
- # error handling specifics are tied to the message posting method. Incorrect behavior
39
- # in an +#on_error+ override can lead to inconsistent +Actor+ behavior that may lead
40
- # to confusion and difficult debugging.
41
- #
42
- # The +Actor+ superclass mixes in the Ruby standard library
43
- # {http://ruby-doc.org/stdlib-2.0/libdoc/observer/rdoc/Observable.html Observable}
44
- # module to provide consistent callbacks upon message processing completion. The normal
45
- # +Observable+ methods, including +#add_observer+ behave normally. Once an observer
46
- # is added to an +Actor+ it will be notified of all messages processed *after*
47
- # addition. Notification will *not* occur for any messages that have already been
48
- # processed.
49
- #
50
- # Observers will be notified regardless of whether the message processing is successful
51
- # or not. The +#update+ method of the observer will receive four arguments. The
52
- # appropriate method signature is:
53
- #
54
- # def update(time, message, result, reason)
55
- #
56
- # These four arguments represent:
57
- #
58
- # * The time that message processing was completed
59
- # * An array containing all elements of the original message, in order
60
- # * The result of the call to +#act+ (will be +nil+ if an exception was raised)
61
- # * Any exception raised by +#act+ (or +nil+ if message processing was successful)
62
- #
63
- # @example Actor Ping Pong
64
- # class Ping < Concurrent::Actor
65
- #
66
- # def initialize(count, pong)
67
- # super()
68
- # @pong = pong
69
- # @remaining = count
70
- # end
71
- #
72
- # def act(msg)
73
- #
74
- # if msg == :pong
75
- # print "Ping: pong\n" if @remaining % 1000 == 0
76
- # @pong.post(:ping)
77
- #
78
- # if @remaining > 0
79
- # @pong << :ping
80
- # @remaining -= 1
81
- # else
82
- # print "Ping :stop\n"
83
- # @pong << :stop
84
- # self.stop
85
- # end
86
- # end
87
- # end
88
- # end
89
- #
90
- # class Pong < Concurrent::Actor
91
- #
92
- # attr_writer :ping
93
- #
94
- # def initialize
95
- # super()
96
- # @count = 0
97
- # end
98
- #
99
- # def act(msg)
100
- #
101
- # if msg == :ping
102
- # print "Pong: ping\n" if @count % 1000 == 0
103
- # @ping << :pong
104
- # @count += 1
105
- #
106
- # elsif msg == :stop
107
- # print "Pong :stop\n"
108
- # self.stop
109
- # end
110
- # end
111
- # end
112
- #
113
- # pong = Pong.new
114
- # ping = Ping.new(10000, pong)
115
- # pong.ping = ping
116
- #
117
- # t1 = ping.run!
118
- # t2 = pong.run!
119
- #
120
- # ping << :pong
121
- #
122
- # @deprecated +Actor+ is being replaced with a completely new framework prior to v1.0.0
123
- #
124
- # @see http://ruby-doc.org/stdlib-2.0/libdoc/observer/rdoc/Observable.html
125
- class Actor
126
- include ::Observable
127
- include Postable
128
- include Runnable
129
-
130
- private
131
-
132
- # @!visibility private
133
- class Poolbox # :nodoc:
134
- include Postable
135
-
136
- def initialize(queue)
137
- @queue = queue
138
- end
139
- end
140
-
141
- public
142
-
143
- # Create a pool of actors that share a common mailbox.
144
- #
145
- # Every +Actor+ instance operates on its own thread. When one thread isn't enough capacity
146
- # to manage all the messages being sent to an +Actor+ a *pool* can be used instead. A pool
147
- # is a collection of +Actor+ instances, all of the same type, that shate a message queue.
148
- # Messages from other threads are all sent to a single queue against which all +Actor+s
149
- # load balance.
150
- #
151
- # @param [Integer] count the number of actors in the pool
152
- # @param [Array] args zero or more arguments to pass to each actor in the pool
153
- #
154
- # @return [Array] two-element array with the shared mailbox as the first element
155
- # and an array of actors as the second element
156
- #
157
- # @raise ArgumentError if +count+ is zero or less
158
- #
159
- # @example
160
- # class EchoActor < Concurrent::Actor
161
- # def act(*message)
162
- # puts "#{message} handled by #{self}"
163
- # end
164
- # end
165
- #
166
- # mailbox, pool = EchoActor.pool(5)
167
- # pool.each{|echo| echo.run! }
168
- #
169
- # 10.times{|i| mailbox.post(i) }
170
- # #=> [0] handled by #<EchoActor:0x007fc8014fb8b8>
171
- # #=> [1] handled by #<EchoActor:0x007fc8014fb890>
172
- # #=> [2] handled by #<EchoActor:0x007fc8014fb868>
173
- # #=> [3] handled by #<EchoActor:0x007fc8014fb890>
174
- # #=> [4] handled by #<EchoActor:0x007fc8014fb840>
175
- # #=> [5] handled by #<EchoActor:0x007fc8014fb8b8>
176
- # #=> [6] handled by #<EchoActor:0x007fc8014fb8b8>
177
- # #=> [7] handled by #<EchoActor:0x007fc8014fb818>
178
- # #=> [8] handled by #<EchoActor:0x007fc8014fb890>
179
- #
180
- # @deprecated +Actor+ is being replaced with a completely new framework prior to v1.0.0
181
- def self.pool(count, *args, &block)
182
- warn '[DEPRECATED] `Actor` is deprecated and will be replaced with `Actress`.'
183
- raise ArgumentError.new('count must be greater than zero') unless count > 0
184
- mailbox = Queue.new
185
- actors = count.times.collect do
186
- if block_given?
187
- actor = self.new(*args, &block.dup)
188
- else
189
- actor = self.new(*args)
190
- end
191
- actor.instance_variable_set(:@queue, mailbox)
192
- actor
193
- end
194
- return Poolbox.new(mailbox), actors
195
- end
196
-
197
- protected
198
-
199
- # Actors are defined by subclassing the +Concurrent::Actor+ class and overriding the
200
- # #act method. The #act method can have any signature/arity but +def act(*args)+
201
- # is the most flexible and least error-prone signature. The #act method is called in
202
- # response to a message being post to the +Actor+ instance (see *Behavior* below).
203
- #
204
- # @param [Array] message one or more arguments representing the message sent to the
205
- # actor via one of the Concurrent::Postable methods
206
- #
207
- # @return [Object] the result obtained when the message is successfully processed
208
- #
209
- # @raise NotImplementedError unless overridden in the +Actor+ subclass
210
- #
211
- # @deprecated +Actor+ is being replaced with a completely new framework prior to v1.0.0
212
- #
213
- # @!visibility public
214
- def act(*message)
215
- warn '[DEPRECATED] `Actor` is deprecated and will be replaced with `Actress`.'
216
- raise NotImplementedError.new("#{self.class} does not implement #act")
217
- end
218
-
219
- # @!visibility private
220
- #
221
- # @deprecated +Actor+ is being replaced with a completely new framework prior to v1.0.0
222
- def on_run # :nodoc:
223
- warn '[DEPRECATED] `Actor` is deprecated and will be replaced with `Actress`.'
224
- queue.clear
225
- end
226
-
227
- # @!visibility private
228
- #
229
- # @deprecated +Actor+ is being replaced with a completely new framework prior to v1.0.0
230
- def on_stop # :nodoc:
231
- queue.clear
232
- queue.push(:stop)
233
- end
234
-
235
- # @!visibility private
236
- #
237
- # @deprecated +Actor+ is being replaced with a completely new framework prior to v1.0.0
238
- def on_task # :nodoc:
239
- package = queue.pop
240
- return if package == :stop
241
- result = ex = nil
242
- notifier = package.notifier
243
- begin
244
- if notifier.nil? || (notifier.is_a?(Event) && ! notifier.set?)
245
- result = act(*package.message)
246
- end
247
- rescue => ex
248
- on_error(Time.now, package.message, ex)
249
- ensure
250
- if notifier.is_a?(Event) && ! notifier.set?
251
- package.handler.push(result || ex)
252
- package.notifier.set
253
- elsif package.handler.is_a?(IVar)
254
- package.handler.complete(! result.nil?, result, ex)
255
- elsif package.handler.respond_to?(:post) && ex.nil?
256
- package.handler.post(result)
257
- end
258
-
259
- changed
260
- notify_observers(Time.now, package.message, result, ex)
261
- end
262
- end
263
-
264
- # @!visibility private
265
- #
266
- # @deprecated +Actor+ is being replaced with a completely new framework prior to v1.0.0
267
- def on_error(time, msg, ex) # :nodoc:
268
- end
269
- end
270
- end
@@ -1,102 +0,0 @@
1
- require 'concurrent/atomic/event'
2
-
3
- module Concurrent
4
-
5
- module Postable
6
-
7
- # @!visibility private
8
- Package = Struct.new(:message, :handler, :notifier) # :nodoc:
9
-
10
- # Sends a message to and returns. It's a fire-and-forget interaction.
11
- #
12
- # @param [Array] message one or more arguments representing a single message
13
- # to be sent to the receiver.
14
- #
15
- # @return [Object] false when the message cannot be queued else the number
16
- # of messages in the queue *after* this message has been post
17
- #
18
- # @raise ArgumentError when the message is empty
19
- #
20
- # @example
21
- # class EchoActor < Concurrent::Actor
22
- # def act(*message)
23
- # p message
24
- # end
25
- # end
26
- #
27
- # echo = EchoActor.new
28
- # echo.run!
29
- #
30
- # echo.post("Don't panic") #=> true
31
- # #=> ["Don't panic"]
32
- #
33
- # echo.post(1, 2, 3, 4, 5) #=> true
34
- # #=> [1, 2, 3, 4, 5]
35
- #
36
- # echo << "There's a frood who really knows where his towel is." #=> #<EchoActor:0x007fc8012b8448...
37
- # #=> ["There's a frood who really knows where his towel is."]
38
- def post(*message)
39
- raise ArgumentError.new('empty message') if message.empty?
40
- return false unless ready?
41
- queue.push(Package.new(message))
42
- true
43
- end
44
-
45
- def <<(message)
46
- post(*message)
47
- self
48
- end
49
-
50
- def post?(*message)
51
- raise ArgumentError.new('empty message') if message.empty?
52
- return nil unless ready?
53
- ivar = IVar.new
54
- queue.push(Package.new(message, ivar))
55
- ivar
56
- end
57
-
58
- def post!(seconds, *message)
59
- raise ArgumentError.new('empty message') if message.empty?
60
- raise Concurrent::LifecycleError unless ready?
61
- raise Concurrent::TimeoutError if seconds.to_f <= 0.0
62
- event = Event.new
63
- cback = Queue.new
64
- queue.push(Package.new(message, cback, event))
65
- if event.wait(seconds)
66
- result = cback.pop
67
- if result.is_a?(Exception)
68
- raise result
69
- else
70
- return result
71
- end
72
- else
73
- event.set # attempt to cancel
74
- raise Concurrent::TimeoutError
75
- end
76
- end
77
-
78
- # @deprecated +Actor+ is being replaced with a completely new framework prior to v1.0.0
79
- def forward(receiver, *message)
80
- raise ArgumentError.new('empty message') if message.empty?
81
- return false unless ready?
82
- queue.push(Package.new(message, receiver))
83
- queue.length
84
- end
85
-
86
- # @deprecated +Actor+ is being replaced with a completely new framework prior to v1.0.0
87
- def ready?
88
- if self.respond_to?(:running?) && ! running?
89
- false
90
- else
91
- true
92
- end
93
- end
94
-
95
- private
96
-
97
- # @!visibility private
98
- def queue # :nodoc:
99
- @queue ||= Queue.new
100
- end
101
- end
102
- end
@@ -1,2 +0,0 @@
1
- require 'concurrent/actor/actor'
2
- require 'concurrent/actor/postable'
@@ -1,48 +0,0 @@
1
- module Concurrent
2
-
3
- class MutexAtomic
4
-
5
- def initialize(init = nil)
6
- @value = init
7
- @mutex = Mutex.new
8
- end
9
-
10
- def value
11
- @mutex.lock
12
- @value
13
- ensure
14
- @mutex.unlock
15
- end
16
-
17
- def value=(value)
18
- @mutex.lock
19
- @value = value
20
- ensure
21
- @mutex.unlock
22
- end
23
-
24
- def modify
25
- @mutex.lock
26
- result = yield @value
27
- @value = result
28
- ensure
29
- @mutex.unlock
30
- end
31
-
32
- def compare_and_set(expect, update)
33
- @mutex.lock
34
- if @value == expect
35
- @value = update
36
- true
37
- else
38
- false
39
- end
40
- ensure
41
- @mutex.unlock
42
- end
43
- end
44
-
45
- class Atomic < MutexAtomic
46
- end
47
-
48
- end
@@ -1,90 +0,0 @@
1
- require 'thread'
2
-
3
- require 'concurrent/errors'
4
-
5
- module Concurrent
6
-
7
- module Runnable
8
-
9
- class Context
10
- attr_reader :runner, :thread
11
- def initialize(runner)
12
- @runner = runner
13
- @thread = Thread.new(runner) do |runner|
14
- Thread.abort_on_exception = false
15
- runner.run
16
- end
17
- @thread.join(0.1) # let the thread start
18
- end
19
- end
20
-
21
- def self.included(base)
22
-
23
- class << base
24
-
25
- def run!(*args, &block)
26
- runner = self.new(*args, &block)
27
- return Context.new(runner)
28
- rescue => ex
29
- return nil
30
- end
31
- end
32
- end
33
-
34
- def run!(abort_on_exception = false)
35
- raise LifecycleError.new('already running') if @running
36
- thread = Thread.new do
37
- Thread.current.abort_on_exception = abort_on_exception
38
- self.run
39
- end
40
- thread.join(0.1) # let the thread start
41
- return thread
42
- end
43
-
44
- def run
45
- mutex.synchronize do
46
- raise LifecycleError.new('already running') if @running
47
- raise LifecycleError.new('#on_task not implemented') unless self.respond_to?(:on_task, true)
48
- on_run if respond_to?(:on_run, true)
49
- @running = true
50
- end
51
-
52
- loop do
53
- break unless @running
54
- on_task
55
- break unless @running
56
- Thread.pass
57
- end
58
-
59
- after_run if respond_to?(:after_run, true)
60
- return true
61
- rescue LifecycleError => ex
62
- @running = false
63
- raise ex
64
- rescue => ex
65
- @running = false
66
- return false
67
- end
68
-
69
- def stop
70
- return true unless @running
71
- mutex.synchronize do
72
- @running = false
73
- on_stop if respond_to?(:on_stop, true)
74
- end
75
- return true
76
- rescue => ex
77
- return false
78
- end
79
-
80
- def running?
81
- return @running == true
82
- end
83
-
84
- protected
85
-
86
- def mutex
87
- @mutex ||= Mutex.new
88
- end
89
- end
90
- end