concurrent-ruby 0.6.0 → 0.7.0.rc0

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 (110) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +55 -51
  3. data/lib/concurrent/actress/ad_hoc.rb +6 -0
  4. data/lib/concurrent/actress/context.rb +10 -8
  5. data/lib/concurrent/actress/core.rb +44 -20
  6. data/lib/concurrent/actress/core_delegations.rb +5 -0
  7. data/lib/concurrent/actress/envelope.rb +21 -5
  8. data/lib/concurrent/actress/reference.rb +5 -5
  9. data/lib/concurrent/actress.rb +152 -6
  10. data/lib/concurrent/agent.rb +9 -9
  11. data/lib/concurrent/atomic.rb +46 -0
  12. data/lib/concurrent/atomic_reference/concurrent_update_error.rb +7 -0
  13. data/lib/concurrent/atomic_reference/delegated_update.rb +28 -0
  14. data/lib/concurrent/atomic_reference/direct_update.rb +28 -0
  15. data/lib/concurrent/atomic_reference/jruby.rb +8 -0
  16. data/lib/concurrent/atomic_reference/mutex_atomic.rb +47 -0
  17. data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +24 -0
  18. data/lib/concurrent/atomic_reference/rbx.rb +16 -0
  19. data/lib/concurrent/atomic_reference/ruby.rb +16 -0
  20. data/lib/concurrent/atomics.rb +1 -1
  21. data/lib/concurrent/configuration.rb +7 -2
  22. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +0 -1
  23. data/lib/concurrent/executor/{one_by_one.rb → serialized_execution.rb} +21 -8
  24. data/lib/concurrent/executor/timer_set.rb +6 -1
  25. data/lib/concurrent/executors.rb +1 -1
  26. data/lib/concurrent/logging.rb +1 -1
  27. data/lib/concurrent/observable.rb +1 -1
  28. data/lib/concurrent/supervisor.rb +1 -1
  29. data/lib/concurrent/timer_task.rb +0 -36
  30. data/lib/concurrent/version.rb +1 -1
  31. data/lib/concurrent.rb +3 -4
  32. data/lib/concurrent_ruby_ext.so +0 -0
  33. data/lib/extension_helper.rb +9 -0
  34. metadata +19 -152
  35. data/lib/concurrent/actor/actor.rb +0 -270
  36. data/lib/concurrent/actor/postable.rb +0 -102
  37. data/lib/concurrent/actors.rb +0 -2
  38. data/lib/concurrent/actress/doc.md +0 -53
  39. data/lib/concurrent/atomic/atomic.rb +0 -48
  40. data/lib/concurrent/runnable.rb +0 -90
  41. data/lib/concurrent/stoppable.rb +0 -20
  42. data/spec/concurrent/actor/actor_spec.rb +0 -376
  43. data/spec/concurrent/actor/postable_shared.rb +0 -218
  44. data/spec/concurrent/actress_spec.rb +0 -191
  45. data/spec/concurrent/agent_spec.rb +0 -500
  46. data/spec/concurrent/async_spec.rb +0 -352
  47. data/spec/concurrent/atomic/atomic_boolean_spec.rb +0 -172
  48. data/spec/concurrent/atomic/atomic_fixnum_spec.rb +0 -186
  49. data/spec/concurrent/atomic/atomic_spec.rb +0 -133
  50. data/spec/concurrent/atomic/condition_spec.rb +0 -171
  51. data/spec/concurrent/atomic/copy_on_notify_observer_set_spec.rb +0 -10
  52. data/spec/concurrent/atomic/copy_on_write_observer_set_spec.rb +0 -10
  53. data/spec/concurrent/atomic/count_down_latch_spec.rb +0 -151
  54. data/spec/concurrent/atomic/cyclic_barrier_spec.rb +0 -248
  55. data/spec/concurrent/atomic/event_spec.rb +0 -200
  56. data/spec/concurrent/atomic/observer_set_shared.rb +0 -242
  57. data/spec/concurrent/atomic/thread_local_var_spec.rb +0 -113
  58. data/spec/concurrent/channel/buffered_channel_spec.rb +0 -151
  59. data/spec/concurrent/channel/channel_spec.rb +0 -39
  60. data/spec/concurrent/channel/probe_spec.rb +0 -77
  61. data/spec/concurrent/channel/unbuffered_channel_spec.rb +0 -132
  62. data/spec/concurrent/collection/blocking_ring_buffer_spec.rb +0 -149
  63. data/spec/concurrent/collection/priority_queue_spec.rb +0 -317
  64. data/spec/concurrent/collection/ring_buffer_spec.rb +0 -126
  65. data/spec/concurrent/configuration_spec.rb +0 -71
  66. data/spec/concurrent/dataflow_spec.rb +0 -242
  67. data/spec/concurrent/delay_spec.rb +0 -91
  68. data/spec/concurrent/dereferenceable_shared.rb +0 -146
  69. data/spec/concurrent/exchanger_spec.rb +0 -66
  70. data/spec/concurrent/executor/cached_thread_pool_shared.rb +0 -115
  71. data/spec/concurrent/executor/fixed_thread_pool_shared.rb +0 -136
  72. data/spec/concurrent/executor/global_thread_pool_shared.rb +0 -35
  73. data/spec/concurrent/executor/immediate_executor_spec.rb +0 -12
  74. data/spec/concurrent/executor/java_cached_thread_pool_spec.rb +0 -44
  75. data/spec/concurrent/executor/java_fixed_thread_pool_spec.rb +0 -64
  76. data/spec/concurrent/executor/java_single_thread_executor_spec.rb +0 -21
  77. data/spec/concurrent/executor/java_thread_pool_executor_spec.rb +0 -71
  78. data/spec/concurrent/executor/per_thread_executor_spec.rb +0 -57
  79. data/spec/concurrent/executor/ruby_cached_thread_pool_spec.rb +0 -69
  80. data/spec/concurrent/executor/ruby_fixed_thread_pool_spec.rb +0 -39
  81. data/spec/concurrent/executor/ruby_single_thread_executor_spec.rb +0 -18
  82. data/spec/concurrent/executor/ruby_thread_pool_executor_spec.rb +0 -171
  83. data/spec/concurrent/executor/safe_task_executor_spec.rb +0 -103
  84. data/spec/concurrent/executor/thread_pool_class_cast_spec.rb +0 -52
  85. data/spec/concurrent/executor/thread_pool_executor_shared.rb +0 -155
  86. data/spec/concurrent/executor/thread_pool_shared.rb +0 -239
  87. data/spec/concurrent/executor/timer_set_spec.rb +0 -183
  88. data/spec/concurrent/future_spec.rb +0 -329
  89. data/spec/concurrent/ivar_spec.rb +0 -215
  90. data/spec/concurrent/mvar_spec.rb +0 -380
  91. data/spec/concurrent/obligation_shared.rb +0 -102
  92. data/spec/concurrent/obligation_spec.rb +0 -282
  93. data/spec/concurrent/observable_shared.rb +0 -177
  94. data/spec/concurrent/observable_spec.rb +0 -56
  95. data/spec/concurrent/options_parser_spec.rb +0 -71
  96. data/spec/concurrent/promise_spec.rb +0 -367
  97. data/spec/concurrent/runnable_shared.rb +0 -68
  98. data/spec/concurrent/runnable_spec.rb +0 -235
  99. data/spec/concurrent/scheduled_task_spec.rb +0 -342
  100. data/spec/concurrent/stoppable_shared.rb +0 -37
  101. data/spec/concurrent/supervisor_spec.rb +0 -1148
  102. data/spec/concurrent/timer_task_spec.rb +0 -258
  103. data/spec/concurrent/tvar_spec.rb +0 -137
  104. data/spec/concurrent/utility/processor_count_spec.rb +0 -20
  105. data/spec/concurrent/utility/timeout_spec.rb +0 -50
  106. data/spec/concurrent/utility/timer_spec.rb +0 -52
  107. data/spec/spec_helper.rb +0 -31
  108. data/spec/support/example_group_extensions.rb +0 -48
  109. data/spec/support/less_than_or_equal_to_matcher.rb +0 -5
  110. /data/{LICENSE → LICENSE.txt} +0 -0
@@ -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
@@ -1,20 +0,0 @@
1
- require 'concurrent/runnable'
2
-
3
- module Concurrent
4
-
5
- module Stoppable
6
-
7
- def before_stop(&block)
8
- raise ArgumentError.new('no block given') unless block_given?
9
- raise Runnable::LifecycleError.new('#before_stop already set') if @before_stop_proc
10
- @before_stop_proc = block
11
- self
12
- end
13
-
14
- protected
15
-
16
- def before_stop_proc
17
- @before_stop_proc
18
- end
19
- end
20
- end
@@ -1,376 +0,0 @@
1
- require 'spec_helper'
2
- require_relative 'postable_shared'
3
- require_relative '../runnable_shared'
4
-
5
- module Concurrent
6
-
7
- describe Actor do
8
-
9
- before do
10
- # suppress deprecation warnings.
11
- Concurrent::Actor.any_instance.stub(:warn)
12
- Concurrent::Actor.stub(:warn)
13
- end
14
-
15
- let(:actor_class) do
16
- Class.new(Actor) do
17
- attr_reader :last_message
18
- def initialize(&block)
19
- @task = block
20
- super()
21
- end
22
- def act(*message)
23
- @last_message = message
24
- @task.call(*message) unless @task.nil?
25
- end
26
- end
27
- end
28
-
29
- ## :runnable
30
- subject { Class.new(actor_class).new }
31
- it_should_behave_like :runnable
32
-
33
- ## :postable
34
-
35
- let!(:postable_class){ actor_class }
36
-
37
- let(:sender_class) do
38
- Class.new(Actor) do
39
- def act(*message)
40
- if message.first.is_a?(Exception)
41
- raise message.first
42
- else
43
- return message.first
44
- end
45
- end
46
- end
47
- end
48
-
49
- let(:sender) { sender_class.new }
50
- let(:receiver) { postable_class.new }
51
-
52
- it_should_behave_like :postable
53
-
54
- context '#run' do
55
-
56
- it 'empties the queue' do
57
- @thread = Thread.new{ subject.run }
58
- @thread.join(0.1)
59
- q = subject.instance_variable_get(:@queue)
60
- q.size.should == 0
61
- end
62
- end
63
-
64
- context '#stop' do
65
-
66
- it 'empties the queue' do
67
- actor = actor_class.new{|msg| sleep }
68
- @thread = Thread.new{ actor.run }
69
- 10.times { actor.post(true) }
70
- @thread.join(0.1)
71
- actor.stop
72
- @thread.join(0.1)
73
- q = actor.instance_variable_get(:@queue)
74
- if q.size >= 1
75
- q.pop.should == :stop
76
- else
77
- q.size.should == 0
78
- end
79
- end
80
-
81
- it 'pushes a :stop message onto the queue' do
82
- @thread = Thread.new{ subject.run }
83
- @thread.join(0.1)
84
- q = subject.instance_variable_get(:@queue)
85
- q.should_receive(:push).once.with(:stop)
86
- subject.stop
87
- @thread.join(0.1)
88
- end
89
- end
90
-
91
- context 'exception handling' do
92
-
93
- #it 'supresses exceptions thrown when handling messages' do
94
- #pending('intermittently failing; deprecated')
95
- #actor = actor_class.new{|msg| raise StandardError }
96
- #@thread = Thread.new{ actor.run }
97
- #expect {
98
- #@thread.join(0.1)
99
- #10.times { actor.post(true) }
100
- #}.not_to raise_error
101
- #actor.stop
102
- #end
103
- end
104
-
105
- context 'observation' do
106
-
107
- let(:actor_class) do
108
- Class.new(Actor) do
109
- def act(*message)
110
- if message.first.is_a?(Exception)
111
- raise message.first
112
- else
113
- return message.first
114
- end
115
- end
116
- end
117
- end
118
-
119
- subject { Class.new(actor_class).new }
120
-
121
- let(:observer) do
122
- Class.new {
123
- attr_reader :time
124
- attr_reader :message
125
- attr_reader :value
126
- attr_reader :reason
127
- def update(time, message, value, reason)
128
- @time = time
129
- @message = message
130
- @value = value
131
- @reason = reason
132
- end
133
- }.new
134
- end
135
-
136
- #it 'notifies observers when a message is successfully handled' do
137
- #pending('intermittently failing; deprecated')
138
- #observer.should_receive(:update).exactly(10).times.with(any_args())
139
- #subject.add_observer(observer)
140
- #@thread = Thread.new{ subject.run }
141
- #@thread.join(0.1)
142
- #10.times { subject.post(42) }
143
- #@thread.join(0.1)
144
- #end
145
-
146
- #it 'notifies observers when a message raises an exception' do
147
- #pending('intermittently failing; deprecated')
148
- #error = StandardError.new
149
- #observer.should_receive(:update).exactly(10).times.with(any_args())
150
- #subject.add_observer(observer)
151
- #@thread = Thread.new{ subject.run }
152
- #@thread.join(0.1)
153
- #10.times { subject.post(error) }
154
- #@thread.join(0.1)
155
- #end
156
-
157
- it 'passes the time, message, value, and reason to the observer on success' do
158
- subject.add_observer(observer)
159
- @thread = Thread.new{ subject.run }
160
- @thread.join(0.1)
161
- subject.post(42)
162
- @thread.join(0.1)
163
-
164
- observer.time.should be_a(Time)
165
- observer.message.should eq [42]
166
- observer.value.should eq 42
167
- observer.reason.should be_nil
168
- end
169
-
170
- it 'passes the time, message, value, and reason to the observer on exception' do
171
- error = StandardError.new
172
- subject.add_observer(observer)
173
- @thread = Thread.new{ subject.run }
174
- @thread.join(0.1)
175
- subject.post(error)
176
- @thread.join(0.1)
177
-
178
- observer.time.should be_a(Time)
179
- observer.message.should eq [error]
180
- observer.value.should be_nil
181
- observer.reason.should be_a(Exception)
182
- end
183
- end
184
-
185
- context '#pool' do
186
-
187
- let(:clazz){ Class.new(actor_class) }
188
-
189
- it 'raises an exception if the count is zero or less' do
190
- expect {
191
- clazz.pool(0)
192
- }.to raise_error(ArgumentError)
193
- end
194
-
195
- it 'creates the requested number of pool' do
196
- mailbox, pool = clazz.pool(5)
197
- pool.size.should == 5
198
- end
199
-
200
- it 'passes all optional arguments to the individual constructors' do
201
- clazz.should_receive(:new).with(1, 2, 3).exactly(5).times
202
- clazz.pool(5, 1, 2, 3)
203
- end
204
-
205
- it 'passes a duplicate of the given block to each actor in the pool' do
206
- block = proc{ nil }
207
- block.should_receive(:dup).exactly(5).times.and_return(proc{ nil })
208
- mailbox, pool = clazz.pool(5, &block)
209
- end
210
-
211
- it 'gives all pool the same mailbox' do
212
- mailbox, pool = clazz.pool(2)
213
- mbox1 = pool.first.instance_variable_get(:@queue)
214
- mbox2 = pool.last.instance_variable_get(:@queue)
215
- mbox1.should eq mbox2
216
- end
217
-
218
- it 'returns a Poolbox as the first retval' do
219
- mailbox, pool = clazz.pool(2)
220
- mailbox.should be_a(Actor::Poolbox)
221
- end
222
-
223
- it 'gives the Poolbox the same mailbox as the pool' do
224
- mailbox, pool = clazz.pool(1)
225
- mbox1 = mailbox.instance_variable_get(:@queue)
226
- mbox2 = pool.first.instance_variable_get(:@queue)
227
- mbox1.should eq mbox2
228
- end
229
-
230
- it 'returns an array of pool as the second retval' do
231
- mailbox, pool = clazz.pool(2)
232
- pool.each do |actor|
233
- actor.should be_a(clazz)
234
- end
235
- end
236
-
237
- it 'posts to the mailbox with Poolbox#post' do
238
- mailbox, pool = clazz.pool(1)
239
- @thread = Thread.new{ pool.first.run }
240
- sleep(0.1)
241
- mailbox.post(42)
242
- sleep(0.1)
243
- pool.first.last_message.should eq [42]
244
- pool.first.stop
245
- @thread.kill
246
- end
247
-
248
- #it 'posts to the mailbox with Poolbox#<<' do
249
- #pending('intermittently failing; deprecated')
250
- #@expected = false
251
- #mailbox, pool = clazz.pool(1)
252
- #@thread = Thread.new{ pool.first.run }
253
- #sleep(0.1)
254
- #mailbox << 42
255
- #sleep(0.1)
256
- #pool.first.last_message.should eq [42]
257
- #pool.first.stop
258
- #@thread.kill
259
- #end
260
- end
261
-
262
- context 'subclassing' do
263
-
264
- after(:each) do
265
- @thread.kill unless @thread.nil?
266
- end
267
-
268
- context '#pool' do
269
-
270
- it 'creates pool of the appropriate subclass' do
271
- actor = Class.new(actor_class)
272
- mailbox, pool = actor.pool(1)
273
- pool.first.should be_a(actor)
274
- end
275
- end
276
-
277
- context '#act overloading' do
278
-
279
- it 'raises an exception if #act is not implemented in the subclass' do
280
- actor = Class.new(Actor).new
281
- @thread = Thread.new{ actor.run }
282
- @thread.join(0.1)
283
- expect {
284
- actor.post(:foo)
285
- @thread.join(0.1)
286
- }.to raise_error(NotImplementedError)
287
- actor.stop
288
- end
289
-
290
- it 'uses the subclass #act implementation' do
291
- actor = actor_class.new{|*args| @expected = true }
292
- @thread = Thread.new{ actor.run }
293
- @thread.join(0.1)
294
- actor.post(:foo)
295
- @thread.join(0.1)
296
- actor.last_message.should eq [:foo]
297
- actor.stop
298
- end
299
- end
300
-
301
- context '#on_error overloading' do
302
-
303
- let(:bad_actor) do
304
- Class.new(actor_class) {
305
- attr_reader :last_error
306
- def act(*message)
307
- raise StandardError
308
- end
309
- def on_error(*args)
310
- @last_error = args
311
- end
312
- }
313
- end
314
-
315
- it 'uses the subclass #on_error implementation' do
316
- actor = bad_actor.new
317
- @thread = Thread.new{ actor.run }
318
- @thread.join(0.1)
319
- actor.post(42)
320
- @thread.join(0.1)
321
- actor.last_error[0].should be_a(Time)
322
- actor.last_error[1].should eq [42]
323
- actor.last_error[2].should be_a(StandardError)
324
- actor.stop
325
- end
326
- end
327
- end
328
-
329
- context 'supervision' do
330
-
331
- it 'can be started by a Supervisor' do
332
- actor = actor_class.new
333
- supervisor = Supervisor.new
334
- supervisor.add_worker(actor)
335
-
336
- actor.should_receive(:run).with(no_args())
337
- supervisor.run!
338
- sleep(0.1)
339
-
340
- supervisor.stop
341
- sleep(0.1)
342
- actor.stop
343
- end
344
-
345
- it 'can receive messages while under supervision' do
346
- @expected = false
347
- actor = actor_class.new{|*args| @expected = true}
348
- supervisor = Supervisor.new
349
- supervisor.add_worker(actor)
350
- supervisor.run!
351
- sleep(0.1)
352
-
353
- actor.post(42)
354
- sleep(0.1)
355
- @expected.should be_true
356
-
357
- supervisor.stop
358
- sleep(0.1)
359
- actor.stop
360
- end
361
-
362
- it 'can be stopped by a supervisor' do
363
- actor = actor_class.new
364
- supervisor = Supervisor.new
365
- supervisor.add_worker(actor)
366
-
367
- supervisor.run!
368
- sleep(0.1)
369
-
370
- actor.should_receive(:stop).with(no_args())
371
- supervisor.stop
372
- sleep(0.1)
373
- end
374
- end
375
- end
376
- end