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,103 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module Concurrent
4
-
5
- describe SafeTaskExecutor do
6
-
7
- describe '#execute' do
8
-
9
- context 'happy execution' do
10
-
11
- let(:task) { Proc.new { 42 } }
12
- subject { SafeTaskExecutor.new(task) }
13
-
14
- it 'should return success' do
15
- success, value, reason = subject.execute
16
- success.should be_true
17
- end
18
-
19
- it 'should return task value' do
20
- success, value, reason = subject.execute
21
- value.should eq 42
22
- end
23
-
24
- it 'should return a nil reason' do
25
- success, value, reason = subject.execute
26
- reason.should be_nil
27
- end
28
-
29
- it 'passes all arguments to #execute to the task' do
30
- expected = nil
31
- task = proc {|*args| expected = args }
32
- SafeTaskExecutor.new(task).execute(1, 2, 3)
33
- expected.should eq [1, 2, 3]
34
- end
35
-
36
- it 'protectes #execute with a mutex' do
37
- mutex = double(:mutex)
38
- Mutex.should_receive(:new).with(no_args).and_return(mutex)
39
- mutex.should_receive(:synchronize).with(no_args)
40
- subject.execute
41
- end
42
- end
43
-
44
- context 'failing execution' do
45
-
46
- let(:task) { Proc.new { raise StandardError.new('an error') } }
47
- subject { SafeTaskExecutor.new(task) }
48
-
49
- it 'should return false success' do
50
- success, value, reason = subject.execute
51
- success.should be_false
52
- end
53
-
54
- it 'should return a nil value' do
55
- success, value, reason = subject.execute
56
- value.should be_nil
57
- end
58
-
59
- it 'should return the reason' do
60
- success, value, reason = subject.execute
61
- reason.should be_a(StandardError)
62
- reason.message.should eq 'an error'
63
- end
64
-
65
- it 'rescues Exception when :rescue_exception is true' do
66
- task = proc { raise Exception }
67
- subject = SafeTaskExecutor.new(task, rescue_exception: true)
68
- expect {
69
- subject.execute
70
- }.to_not raise_error
71
- end
72
-
73
- it 'rescues StandardError when :rescue_exception is false' do
74
- task = proc { raise StandardError }
75
- subject = SafeTaskExecutor.new(task, rescue_exception: false)
76
- expect {
77
- subject.execute
78
- }.to_not raise_error
79
-
80
- task = proc { raise Exception }
81
- subject = SafeTaskExecutor.new(task, rescue_exception: false)
82
- expect {
83
- subject.execute
84
- }.to raise_error(Exception)
85
- end
86
-
87
- it 'rescues StandardError by default' do
88
- task = proc { raise StandardError }
89
- subject = SafeTaskExecutor.new(task)
90
- expect {
91
- subject.execute
92
- }.to_not raise_error
93
-
94
- task = proc { raise Exception }
95
- subject = SafeTaskExecutor.new(task)
96
- expect {
97
- subject.execute
98
- }.to raise_error(Exception)
99
- end
100
- end
101
- end
102
- end
103
- end
@@ -1,52 +0,0 @@
1
- require 'spec_helper'
2
-
3
- module Concurrent
4
-
5
- describe SingleThreadExecutor do
6
- if jruby?
7
- it 'inherits from JavaSingleThreadExecutor' do
8
- SingleThreadExecutor.ancestors.should include(JavaSingleThreadExecutor)
9
- end
10
- else
11
- it 'inherits from RubySingleThreadExecutor' do
12
- SingleThreadExecutor.ancestors.should include(RubySingleThreadExecutor)
13
- end
14
- end
15
- end
16
-
17
- describe ThreadPoolExecutor do
18
- if jruby?
19
- it 'inherits from JavaThreadPoolExecutor' do
20
- ThreadPoolExecutor.ancestors.should include(JavaThreadPoolExecutor)
21
- end
22
- else
23
- it 'inherits from RubyThreadPoolExecutor' do
24
- ThreadPoolExecutor.ancestors.should include(RubyThreadPoolExecutor)
25
- end
26
- end
27
- end
28
-
29
- describe CachedThreadPool do
30
- if jruby?
31
- it 'inherits from JavaCachedThreadPool' do
32
- CachedThreadPool.ancestors.should include(JavaCachedThreadPool)
33
- end
34
- else
35
- it 'inherits from RubyCachedThreadPool' do
36
- CachedThreadPool.ancestors.should include(RubyCachedThreadPool)
37
- end
38
- end
39
- end
40
-
41
- describe FixedThreadPool do
42
- if jruby?
43
- it 'inherits from JavaFixedThreadPool' do
44
- FixedThreadPool.ancestors.should include(JavaFixedThreadPool)
45
- end
46
- else
47
- it 'inherits from RubyFixedThreadPool' do
48
- FixedThreadPool.ancestors.should include(RubyFixedThreadPool)
49
- end
50
- end
51
- end
52
- end
@@ -1,155 +0,0 @@
1
- require 'spec_helper'
2
- require_relative 'thread_pool_shared'
3
-
4
- share_examples_for :thread_pool_executor do
5
-
6
- after(:each) do
7
- subject.kill
8
- sleep(0.1)
9
- end
10
-
11
- it_should_behave_like :thread_pool
12
-
13
- context '#initialize' do
14
-
15
- it 'defaults :min_length to DEFAULT_MIN_POOL_SIZE' do
16
- subject = described_class.new
17
- subject.min_length.should eq described_class::DEFAULT_MIN_POOL_SIZE
18
- end
19
-
20
- it 'defaults :max_length to DEFAULT_MAX_POOL_SIZE' do
21
- subject = described_class.new
22
- subject.max_length.should eq described_class::DEFAULT_MAX_POOL_SIZE
23
- end
24
-
25
- it 'defaults :idletime to DEFAULT_THREAD_IDLETIMEOUT' do
26
- subject = described_class.new
27
- subject.idletime.should eq described_class::DEFAULT_THREAD_IDLETIMEOUT
28
- end
29
-
30
- it 'defaults :max_queue to DEFAULT_MAX_QUEUE_SIZE' do
31
- subject = described_class.new
32
- subject.max_queue.should eq described_class::DEFAULT_MAX_QUEUE_SIZE
33
- end
34
-
35
- it 'accepts all valid overflow policies' do
36
- Concurrent::RubyThreadPoolExecutor::OVERFLOW_POLICIES.each do |policy|
37
- subject = described_class.new(overflow_policy: policy)
38
- subject.overflow_policy.should eq policy
39
- end
40
- end
41
-
42
- it 'defaults :overflow_policy to :abort' do
43
- subject = described_class.new
44
- subject.overflow_policy.should eq :abort
45
- end
46
-
47
- it 'raises an exception if :min_threads is less than zero' do
48
- expect {
49
- described_class.new(min_threads: -1)
50
- }.to raise_error(ArgumentError)
51
- end
52
-
53
- it 'raises an exception if :max_threads is not greater than zero' do
54
- expect {
55
- described_class.new(max_threads: 0)
56
- }.to raise_error(ArgumentError)
57
- end
58
-
59
- it 'raises an exception if given an invalid :overflow_policy' do
60
- expect {
61
- described_class.new(overflow_policy: :bogus)
62
- }.to raise_error(ArgumentError)
63
- end
64
- end
65
-
66
- context '#max_queue' do
67
-
68
- let!(:expected_max){ 100 }
69
- subject{ described_class.new(max_queue: expected_max) }
70
-
71
- it 'returns the set value on creation' do
72
- subject.max_queue.should eq expected_max
73
- end
74
-
75
- it 'returns the set value when running' do
76
- 5.times{ subject.post{ sleep(0.1) } }
77
- sleep(0.1)
78
- subject.max_queue.should eq expected_max
79
- end
80
-
81
- it 'returns the set value after stopping' do
82
- 5.times{ subject.post{ sleep(0.1) } }
83
- sleep(0.1)
84
- subject.shutdown
85
- subject.wait_for_termination(1)
86
- subject.max_queue.should eq expected_max
87
- end
88
- end
89
-
90
- context '#queue_length' do
91
-
92
- let!(:expected_max){ 10 }
93
- subject do
94
- described_class.new(
95
- min_threads: 2,
96
- max_threads: 5,
97
- max_queue: expected_max,
98
- overflow_policy: :discard
99
- )
100
- end
101
-
102
- it 'returns zero on creation' do
103
- subject.queue_length.should eq 0
104
- end
105
-
106
- it 'returns zero when there are no enqueued tasks' do
107
- 5.times{ subject.post{ nil } }
108
- sleep(0.1)
109
- subject.queue_length.should eq 0
110
- end
111
-
112
- it 'returns the size of the queue when tasks are enqueued' do
113
- 100.times{ subject.post{ sleep(0.5) } }
114
- sleep(0.1)
115
- subject.queue_length.should > 0
116
- end
117
-
118
- it 'returns zero when stopped' do
119
- 100.times{ subject.post{ sleep(0.5) } }
120
- sleep(0.1)
121
- subject.shutdown
122
- subject.wait_for_termination(1)
123
- subject.queue_length.should eq 0
124
- end
125
-
126
- it 'can never be greater than :max_queue' do
127
- 100.times{ subject.post{ sleep(0.5) } }
128
- sleep(0.1)
129
- subject.queue_length.should <= expected_max
130
- end
131
- end
132
-
133
- context '#remaining_capacity' do
134
-
135
- let!(:expected_max){ 100 }
136
- subject{ described_class.new(max_queue: expected_max) }
137
-
138
- it 'returns -1 when :max_queue is set to zero' do
139
- executor = described_class.new(max_queue: 0)
140
- executor.remaining_capacity.should eq -1
141
- end
142
-
143
- it 'returns :max_length on creation' do
144
- subject.remaining_capacity.should eq expected_max
145
- end
146
-
147
- it 'returns :max_length when stopped' do
148
- 100.times{ subject.post{ nil } }
149
- sleep(0.1)
150
- subject.shutdown
151
- subject.wait_for_termination(1)
152
- subject.remaining_capacity.should eq expected_max
153
- end
154
- end
155
- end
@@ -1,269 +0,0 @@
1
- require 'spec_helper'
2
- require_relative 'global_thread_pool_shared'
3
-
4
- share_examples_for :executor_service do
5
-
6
- after(:each) do
7
- subject.kill
8
- sleep(0.1)
9
- end
10
-
11
- it_should_behave_like :global_thread_pool
12
-
13
- context '#post' do
14
-
15
- it 'rejects the block while shutting down' do
16
- latch = Concurrent::CountDownLatch.new(1)
17
- subject.post{ sleep(1) }
18
- subject.shutdown
19
- subject.post{ latch.count_down }
20
- latch.wait(0.1).should be_false
21
- end
22
-
23
- it 'returns false while shutting down' do
24
- subject.post{ sleep(1) }
25
- subject.shutdown
26
- subject.post{ nil }.should be_false
27
- end
28
-
29
- it 'rejects the block once shutdown' do
30
- subject.shutdown
31
- latch = Concurrent::CountDownLatch.new(1)
32
- subject.post{ sleep(1) }
33
- subject.post{ latch.count_down }
34
- latch.wait(0.1).should be_false
35
- end
36
-
37
- it 'returns false once shutdown' do
38
- subject.post{ nil }
39
- subject.shutdown
40
- sleep(0.1)
41
- subject.post{ nil }.should be_false
42
- end
43
- end
44
-
45
- context '#running?' do
46
-
47
- it 'returns true when the thread pool is running' do
48
- subject.should be_running
49
- end
50
-
51
- it 'returns false when the thread pool is shutting down' do
52
- subject.post{ sleep(1) }
53
- subject.shutdown
54
- subject.wait_for_termination(1)
55
- subject.should_not be_running
56
- end
57
-
58
- it 'returns false when the thread pool is shutdown' do
59
- subject.shutdown
60
- subject.wait_for_termination(1)
61
- subject.should_not be_running
62
- end
63
-
64
- it 'returns false when the thread pool is killed' do
65
- subject.kill
66
- subject.wait_for_termination(1)
67
- subject.should_not be_running
68
- end
69
- end
70
-
71
- context '#shutdown' do
72
-
73
- it 'stops accepting new tasks' do
74
- subject.post{ sleep(1) }
75
- sleep(0.1)
76
- subject.shutdown
77
- @expected = false
78
- subject.post{ @expected = true }.should be_false
79
- sleep(1)
80
- @expected.should be_false
81
- end
82
-
83
- it 'allows in-progress tasks to complete' do
84
- @expected = false
85
- subject.post{ @expected = true }
86
- sleep(0.1)
87
- subject.shutdown
88
- sleep(1)
89
- @expected.should be_true
90
- end
91
-
92
- it 'allows pending tasks to complete' do
93
- @expected = false
94
- subject.post{ sleep(0.2) }
95
- subject.post{ sleep(0.2); @expected = true }
96
- sleep(0.1)
97
- subject.shutdown
98
- sleep(1)
99
- @expected.should be_true
100
- end
101
- end
102
-
103
- context '#shutdown followed by #wait_for_termination' do
104
- it "allows in-progress tasks to complete" do
105
- @expected = false
106
- subject.post{ sleep 0.1; @expected = true }
107
- subject.shutdown
108
- subject.wait_for_termination(1)
109
- @expected.should be_true
110
- end
111
-
112
- it 'allows pending tasks to complete' do
113
- @expected = false
114
- subject.post{ sleep(0.1) }
115
- subject.post{ sleep(0.1); @expected = true }
116
- subject.shutdown
117
- subject.wait_for_termination(1)
118
- @expected.should be_true
119
- end
120
-
121
- it "stops accepting/running new tasks" do
122
- @expected = :start
123
- subject.post{ sleep(0.1) }
124
- subject.post{ sleep(0.1); @expected = :should_be_run }
125
- subject.shutdown
126
- subject.post{ @expected = :should_not_be_run }
127
- subject.wait_for_termination(1)
128
- @expected.should == :should_be_run
129
- end
130
- end
131
-
132
-
133
- context '#kill' do
134
-
135
- it 'stops accepting new tasks' do
136
- subject.post{ sleep(1) }
137
- sleep(0.1)
138
- subject.kill
139
- @expected = false
140
- subject.post{ @expected = true }.should be_false
141
- sleep(1)
142
- @expected.should be_false
143
- end
144
-
145
- it 'rejects all pending tasks' do
146
- subject.post{ sleep(1) }
147
- sleep(0.1)
148
- subject.kill
149
- sleep(0.1)
150
- subject.post{ nil }.should be_false
151
- end
152
- end
153
-
154
- context '#wait_for_termination' do
155
-
156
- it 'immediately returns true when no operations are pending' do
157
- subject.shutdown
158
- subject.wait_for_termination(0).should be_true
159
- end
160
-
161
- it 'returns true after shutdown has complete' do
162
- 10.times { subject << proc{ nil } }
163
- sleep(0.1)
164
- subject.shutdown
165
- subject.wait_for_termination(1).should be_true
166
- end
167
-
168
- it 'returns true when shutdown sucessfully completes before timeout' do
169
- subject.post{ sleep(0.5) }
170
- sleep(0.1)
171
- subject.shutdown
172
- subject.wait_for_termination(1).should be_true
173
- end
174
-
175
- it 'returns false when shutdown fails to complete before timeout' do
176
- 100.times{ subject.post{ sleep(1) } }
177
- sleep(0.1)
178
- subject.shutdown
179
- subject.wait_for_termination(0).should be_false
180
- end
181
- end
182
- end
183
-
184
- share_examples_for :thread_pool do
185
-
186
- after(:each) do
187
- subject.kill
188
- sleep(0.1)
189
- end
190
-
191
- it_should_behave_like :executor_service
192
-
193
- context '#length' do
194
-
195
- it 'returns zero on creation' do
196
- subject.length.should eq 0
197
- end
198
-
199
- it 'returns zero once shut down' do
200
- 5.times{ subject.post{ sleep(0.1) } }
201
- sleep(0.1)
202
- subject.shutdown
203
- subject.wait_for_termination(1)
204
- subject.length.should eq 0
205
- end
206
-
207
- it 'aliased as #current_length' do
208
- 5.times{ subject.post{ sleep(0.1) } }
209
- sleep(0.1)
210
- subject.current_length.should eq subject.length
211
- end
212
- end
213
-
214
- context '#scheduled_task_count' do
215
-
216
- it 'returns zero on creation' do
217
- subject.scheduled_task_count.should eq 0
218
- end
219
-
220
- it 'returns the approximate number of tasks that have been post thus far' do
221
- 10.times{ subject.post{ nil } }
222
- sleep(0.1)
223
- subject.scheduled_task_count.should > 0
224
- end
225
-
226
- it 'returns the approximate number of tasks that were post' do
227
- 10.times{ subject.post{ nil } }
228
- sleep(0.1)
229
- subject.shutdown
230
- subject.wait_for_termination(1)
231
- subject.scheduled_task_count.should > 0
232
- end
233
- end
234
-
235
- context '#completed_task_count' do
236
-
237
- it 'returns zero on creation' do
238
- subject.completed_task_count.should eq 0
239
- end
240
-
241
- it 'returns the approximate number of tasks that have been completed thus far' do
242
- 5.times{ subject.post{ raise StandardError } }
243
- 5.times{ subject.post{ nil } }
244
- sleep(0.1)
245
- subject.completed_task_count.should > 0
246
- end
247
-
248
- it 'returns the approximate number of tasks that were completed' do
249
- 5.times{ subject.post{ raise StandardError } }
250
- 5.times{ subject.post{ nil } }
251
- sleep(0.1)
252
- subject.shutdown
253
- subject.wait_for_termination(1)
254
- subject.completed_task_count.should > 0
255
- end
256
- end
257
-
258
- context '#shutdown' do
259
-
260
- it 'allows threads to exit normally' do
261
- 10.times{ subject << proc{ nil } }
262
- subject.length.should > 0
263
- sleep(0.1)
264
- subject.shutdown
265
- sleep(1)
266
- subject.length.should == 0
267
- end
268
- end
269
- end