concurrent-ruby 0.6.1 → 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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/concurrent.rb +3 -4
- data/lib/concurrent/atomic.rb +46 -0
- data/lib/concurrent/atomic_reference/concurrent_update_error.rb +7 -0
- data/lib/concurrent/atomic_reference/delegated_update.rb +28 -0
- data/lib/concurrent/atomic_reference/direct_update.rb +28 -0
- data/lib/concurrent/atomic_reference/jruby.rb +8 -0
- data/lib/concurrent/atomic_reference/mutex_atomic.rb +47 -0
- data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +24 -0
- data/lib/concurrent/atomic_reference/rbx.rb +16 -0
- data/lib/concurrent/atomic_reference/ruby.rb +16 -0
- data/lib/concurrent/atomics.rb +1 -1
- data/lib/concurrent/configuration.rb +1 -1
- data/lib/concurrent/supervisor.rb +1 -1
- data/lib/concurrent/timer_task.rb +0 -36
- data/lib/concurrent/version.rb +1 -1
- data/lib/concurrent_ruby_ext.so +0 -0
- data/lib/extension_helper.rb +9 -0
- metadata +16 -148
- data/lib/concurrent/actor/actor.rb +0 -270
- data/lib/concurrent/actor/postable.rb +0 -102
- data/lib/concurrent/actors.rb +0 -2
- data/lib/concurrent/atomic/atomic.rb +0 -48
- data/lib/concurrent/runnable.rb +0 -90
- data/lib/concurrent/stoppable.rb +0 -20
- data/spec/concurrent/actor/actor_spec.rb +0 -376
- data/spec/concurrent/actor/postable_shared.rb +0 -218
- data/spec/concurrent/actress_spec.rb +0 -211
- data/spec/concurrent/agent_spec.rb +0 -500
- data/spec/concurrent/async_spec.rb +0 -352
- data/spec/concurrent/atomic/atomic_boolean_spec.rb +0 -172
- data/spec/concurrent/atomic/atomic_fixnum_spec.rb +0 -186
- data/spec/concurrent/atomic/atomic_spec.rb +0 -133
- data/spec/concurrent/atomic/condition_spec.rb +0 -171
- data/spec/concurrent/atomic/copy_on_notify_observer_set_spec.rb +0 -10
- data/spec/concurrent/atomic/copy_on_write_observer_set_spec.rb +0 -10
- data/spec/concurrent/atomic/count_down_latch_spec.rb +0 -151
- data/spec/concurrent/atomic/cyclic_barrier_spec.rb +0 -248
- data/spec/concurrent/atomic/event_spec.rb +0 -200
- data/spec/concurrent/atomic/observer_set_shared.rb +0 -242
- data/spec/concurrent/atomic/thread_local_var_spec.rb +0 -113
- data/spec/concurrent/channel/buffered_channel_spec.rb +0 -151
- data/spec/concurrent/channel/channel_spec.rb +0 -39
- data/spec/concurrent/channel/probe_spec.rb +0 -77
- data/spec/concurrent/channel/unbuffered_channel_spec.rb +0 -132
- data/spec/concurrent/collection/blocking_ring_buffer_spec.rb +0 -149
- data/spec/concurrent/collection/priority_queue_spec.rb +0 -317
- data/spec/concurrent/collection/ring_buffer_spec.rb +0 -126
- data/spec/concurrent/configuration_spec.rb +0 -69
- data/spec/concurrent/dataflow_spec.rb +0 -242
- data/spec/concurrent/delay_spec.rb +0 -91
- data/spec/concurrent/dereferenceable_shared.rb +0 -146
- data/spec/concurrent/exchanger_spec.rb +0 -66
- data/spec/concurrent/executor/cached_thread_pool_shared.rb +0 -115
- data/spec/concurrent/executor/fixed_thread_pool_shared.rb +0 -136
- data/spec/concurrent/executor/global_thread_pool_shared.rb +0 -35
- data/spec/concurrent/executor/immediate_executor_spec.rb +0 -12
- data/spec/concurrent/executor/java_cached_thread_pool_spec.rb +0 -44
- data/spec/concurrent/executor/java_fixed_thread_pool_spec.rb +0 -64
- data/spec/concurrent/executor/java_single_thread_executor_spec.rb +0 -21
- data/spec/concurrent/executor/java_thread_pool_executor_spec.rb +0 -71
- data/spec/concurrent/executor/per_thread_executor_spec.rb +0 -57
- data/spec/concurrent/executor/ruby_cached_thread_pool_spec.rb +0 -69
- data/spec/concurrent/executor/ruby_fixed_thread_pool_spec.rb +0 -39
- data/spec/concurrent/executor/ruby_single_thread_executor_spec.rb +0 -18
- data/spec/concurrent/executor/ruby_thread_pool_executor_spec.rb +0 -171
- data/spec/concurrent/executor/safe_task_executor_spec.rb +0 -103
- data/spec/concurrent/executor/thread_pool_class_cast_spec.rb +0 -52
- data/spec/concurrent/executor/thread_pool_executor_shared.rb +0 -155
- data/spec/concurrent/executor/thread_pool_shared.rb +0 -269
- data/spec/concurrent/executor/timer_set_spec.rb +0 -183
- data/spec/concurrent/future_spec.rb +0 -329
- data/spec/concurrent/ivar_spec.rb +0 -215
- data/spec/concurrent/mvar_spec.rb +0 -380
- data/spec/concurrent/obligation_shared.rb +0 -102
- data/spec/concurrent/obligation_spec.rb +0 -282
- data/spec/concurrent/observable_shared.rb +0 -177
- data/spec/concurrent/observable_spec.rb +0 -56
- data/spec/concurrent/options_parser_spec.rb +0 -71
- data/spec/concurrent/promise_spec.rb +0 -367
- data/spec/concurrent/runnable_shared.rb +0 -68
- data/spec/concurrent/runnable_spec.rb +0 -235
- data/spec/concurrent/scheduled_task_spec.rb +0 -340
- data/spec/concurrent/stoppable_shared.rb +0 -37
- data/spec/concurrent/supervisor_spec.rb +0 -1149
- data/spec/concurrent/timer_task_spec.rb +0 -256
- data/spec/concurrent/tvar_spec.rb +0 -137
- data/spec/concurrent/utility/processor_count_spec.rb +0 -20
- data/spec/concurrent/utility/timeout_spec.rb +0 -50
- data/spec/concurrent/utility/timer_spec.rb +0 -52
- data/spec/spec_helper.rb +0 -41
- data/spec/support/example_group_extensions.rb +0 -52
- data/spec/support/less_than_or_equal_to_matcher.rb +0 -5
@@ -1,215 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require_relative 'dereferenceable_shared'
|
3
|
-
require_relative 'obligation_shared'
|
4
|
-
require_relative 'observable_shared'
|
5
|
-
|
6
|
-
module Concurrent
|
7
|
-
|
8
|
-
describe IVar do
|
9
|
-
|
10
|
-
let!(:value) { 10 }
|
11
|
-
|
12
|
-
subject do
|
13
|
-
i = IVar.new
|
14
|
-
i.set(14)
|
15
|
-
i
|
16
|
-
end
|
17
|
-
|
18
|
-
context 'behavior' do
|
19
|
-
|
20
|
-
# obligation
|
21
|
-
|
22
|
-
let!(:fulfilled_value) { 10 }
|
23
|
-
let(:rejected_reason) { StandardError.new('Boom!') }
|
24
|
-
|
25
|
-
let(:pending_subject) do
|
26
|
-
@i = IVar.new
|
27
|
-
Thread.new do
|
28
|
-
sleep(3)
|
29
|
-
@i.set(fulfilled_value)
|
30
|
-
end
|
31
|
-
@i
|
32
|
-
end
|
33
|
-
|
34
|
-
let(:fulfilled_subject) do
|
35
|
-
i = IVar.new
|
36
|
-
i.set(fulfilled_value)
|
37
|
-
i
|
38
|
-
end
|
39
|
-
|
40
|
-
let(:rejected_subject) do
|
41
|
-
i = IVar.new
|
42
|
-
i.fail(rejected_reason)
|
43
|
-
i
|
44
|
-
end
|
45
|
-
|
46
|
-
it_should_behave_like :obligation
|
47
|
-
|
48
|
-
# dereferenceable
|
49
|
-
|
50
|
-
def dereferenceable_subject(value, opts = {})
|
51
|
-
IVar.new(value, opts)
|
52
|
-
end
|
53
|
-
|
54
|
-
def dereferenceable_observable(opts = {})
|
55
|
-
IVar.new(IVar::NO_VALUE, opts)
|
56
|
-
end
|
57
|
-
|
58
|
-
def execute_dereferenceable(subject)
|
59
|
-
subject.set('value')
|
60
|
-
end
|
61
|
-
|
62
|
-
it_should_behave_like :dereferenceable
|
63
|
-
|
64
|
-
# observable
|
65
|
-
|
66
|
-
subject{ IVar.new }
|
67
|
-
|
68
|
-
def trigger_observable(observable)
|
69
|
-
observable.set('value')
|
70
|
-
end
|
71
|
-
|
72
|
-
it_should_behave_like :observable
|
73
|
-
end
|
74
|
-
|
75
|
-
context '#initialize' do
|
76
|
-
|
77
|
-
it 'does not have to set an initial value' do
|
78
|
-
i = IVar.new
|
79
|
-
i.should be_incomplete
|
80
|
-
end
|
81
|
-
|
82
|
-
it 'does not set an initial value if you pass NO_VALUE' do
|
83
|
-
i = IVar.new(IVar::NO_VALUE)
|
84
|
-
i.should be_incomplete
|
85
|
-
end
|
86
|
-
|
87
|
-
it 'can set an initial value' do
|
88
|
-
i = IVar.new(14)
|
89
|
-
i.should be_completed
|
90
|
-
end
|
91
|
-
|
92
|
-
end
|
93
|
-
|
94
|
-
context '#set' do
|
95
|
-
|
96
|
-
it 'sets the state to be fulfilled' do
|
97
|
-
i = IVar.new
|
98
|
-
i.set(14)
|
99
|
-
i.should be_fulfilled
|
100
|
-
end
|
101
|
-
|
102
|
-
it 'sets the value' do
|
103
|
-
i = IVar.new
|
104
|
-
i.set(14)
|
105
|
-
i.value.should eq 14
|
106
|
-
end
|
107
|
-
|
108
|
-
it 'raises an exception if set more than once' do
|
109
|
-
i = IVar.new
|
110
|
-
i.set(14)
|
111
|
-
expect {i.set(2)}.to raise_error(Concurrent::MultipleAssignmentError)
|
112
|
-
i.value.should eq 14
|
113
|
-
end
|
114
|
-
|
115
|
-
it 'returns self' do
|
116
|
-
i = IVar.new
|
117
|
-
i.set(42).should eq i
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
context '#fail' do
|
122
|
-
|
123
|
-
it 'sets the state to be rejected' do
|
124
|
-
i = IVar.new
|
125
|
-
i.fail
|
126
|
-
i.should be_rejected
|
127
|
-
end
|
128
|
-
|
129
|
-
it 'sets the value to be nil' do
|
130
|
-
i = IVar.new
|
131
|
-
i.fail
|
132
|
-
i.value.should be_nil
|
133
|
-
end
|
134
|
-
|
135
|
-
it 'raises an exception if set more than once' do
|
136
|
-
i = IVar.new
|
137
|
-
i.fail
|
138
|
-
expect {i.fail}.to raise_error(Concurrent::MultipleAssignmentError)
|
139
|
-
i.value.should be_nil
|
140
|
-
end
|
141
|
-
|
142
|
-
it 'defaults the reason to a StandardError' do
|
143
|
-
i = IVar.new
|
144
|
-
i.fail
|
145
|
-
i.reason.should be_a StandardError
|
146
|
-
end
|
147
|
-
|
148
|
-
it 'returns self' do
|
149
|
-
i = IVar.new
|
150
|
-
i.fail.should eq i
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
context 'observation' do
|
155
|
-
|
156
|
-
let(:clazz) do
|
157
|
-
Class.new do
|
158
|
-
attr_reader :value
|
159
|
-
attr_reader :reason
|
160
|
-
attr_reader :count
|
161
|
-
define_method(:update) do |time, value, reason|
|
162
|
-
@count = @count.to_i + 1
|
163
|
-
@value = value
|
164
|
-
@reason = reason
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
let(:observer) { clazz.new }
|
170
|
-
|
171
|
-
it 'notifies all observers on #set' do
|
172
|
-
i = IVar.new
|
173
|
-
i.add_observer(observer)
|
174
|
-
|
175
|
-
i.set(42)
|
176
|
-
|
177
|
-
observer.value.should == 42
|
178
|
-
observer.reason.should be_nil
|
179
|
-
end
|
180
|
-
|
181
|
-
context 'deadlock avoidance' do
|
182
|
-
|
183
|
-
def reentrant_observer(i)
|
184
|
-
obs = Object.new
|
185
|
-
obs.define_singleton_method(:update) do |time, value, reason|
|
186
|
-
@value = i.value
|
187
|
-
end
|
188
|
-
obs.define_singleton_method(:value) { @value }
|
189
|
-
obs
|
190
|
-
end
|
191
|
-
|
192
|
-
it 'should notify observers outside mutex lock' do
|
193
|
-
i = IVar.new
|
194
|
-
obs = reentrant_observer(i)
|
195
|
-
|
196
|
-
i.add_observer(obs)
|
197
|
-
i.set(42)
|
198
|
-
|
199
|
-
obs.value.should eq 42
|
200
|
-
end
|
201
|
-
|
202
|
-
it 'should notify a new observer added after fulfillment outside lock' do
|
203
|
-
i = IVar.new
|
204
|
-
i.set(42)
|
205
|
-
obs = reentrant_observer(i)
|
206
|
-
|
207
|
-
i.add_observer(obs)
|
208
|
-
|
209
|
-
obs.value.should eq 42
|
210
|
-
end
|
211
|
-
end
|
212
|
-
|
213
|
-
end
|
214
|
-
end
|
215
|
-
end
|
@@ -1,380 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require_relative 'dereferenceable_shared'
|
3
|
-
|
4
|
-
module Concurrent
|
5
|
-
|
6
|
-
describe MVar do
|
7
|
-
|
8
|
-
context 'behavior' do
|
9
|
-
|
10
|
-
# dereferenceable
|
11
|
-
|
12
|
-
def dereferenceable_subject(value, opts = {})
|
13
|
-
MVar.new(value, opts)
|
14
|
-
end
|
15
|
-
|
16
|
-
it_should_behave_like :dereferenceable
|
17
|
-
end
|
18
|
-
|
19
|
-
describe '#initialize' do
|
20
|
-
|
21
|
-
it 'accepts no initial value' do
|
22
|
-
m = MVar.new
|
23
|
-
m.should be_empty
|
24
|
-
end
|
25
|
-
|
26
|
-
it 'accepts an empty initial value' do
|
27
|
-
m = MVar.new(MVar::EMPTY)
|
28
|
-
m.should be_empty
|
29
|
-
end
|
30
|
-
|
31
|
-
it 'accepts an initial value' do
|
32
|
-
m = MVar.new(14)
|
33
|
-
m.should_not be_empty
|
34
|
-
end
|
35
|
-
|
36
|
-
it 'accepts a nil initial value' do
|
37
|
-
m = MVar.new(nil)
|
38
|
-
m.should_not be_empty
|
39
|
-
end
|
40
|
-
|
41
|
-
end
|
42
|
-
|
43
|
-
describe '#take' do
|
44
|
-
|
45
|
-
it 'sets the MVar to empty' do
|
46
|
-
m = MVar.new(14)
|
47
|
-
m.take
|
48
|
-
m.should be_empty
|
49
|
-
end
|
50
|
-
|
51
|
-
it 'returns the value on a full MVar' do
|
52
|
-
m = MVar.new(14)
|
53
|
-
m.take.should eq 14
|
54
|
-
end
|
55
|
-
|
56
|
-
it 'waits for another thread to #put' do
|
57
|
-
m = MVar.new
|
58
|
-
|
59
|
-
putter = Thread.new {
|
60
|
-
sleep(0.1)
|
61
|
-
m.put 14
|
62
|
-
}
|
63
|
-
|
64
|
-
m.take.should eq 14
|
65
|
-
end
|
66
|
-
|
67
|
-
it 'returns TIMEOUT on timeout on an empty MVar' do
|
68
|
-
m = MVar.new
|
69
|
-
m.take(0.1).should eq MVar::TIMEOUT
|
70
|
-
end
|
71
|
-
|
72
|
-
end
|
73
|
-
|
74
|
-
describe '#put' do
|
75
|
-
|
76
|
-
it 'sets the MVar to be empty' do
|
77
|
-
m = MVar.new(14)
|
78
|
-
m.take
|
79
|
-
m.should be_empty
|
80
|
-
end
|
81
|
-
|
82
|
-
it 'sets a new value on an empty MVar' do
|
83
|
-
m = MVar.new
|
84
|
-
m.put 14
|
85
|
-
m.take.should eq 14
|
86
|
-
end
|
87
|
-
|
88
|
-
it 'waits for another thread to #take' do
|
89
|
-
m = MVar.new(14)
|
90
|
-
|
91
|
-
putter = Thread.new {
|
92
|
-
sleep(0.1)
|
93
|
-
m.take
|
94
|
-
}
|
95
|
-
|
96
|
-
m.put(14).should eq 14
|
97
|
-
end
|
98
|
-
|
99
|
-
it 'returns TIMEOUT on timeout on a full MVar' do
|
100
|
-
m = MVar.new(14)
|
101
|
-
m.put(14, 0.1).should eq MVar::TIMEOUT
|
102
|
-
end
|
103
|
-
|
104
|
-
it 'returns the value' do
|
105
|
-
m = MVar.new
|
106
|
-
m.put(14).should eq 14
|
107
|
-
end
|
108
|
-
|
109
|
-
end
|
110
|
-
|
111
|
-
describe '#empty?' do
|
112
|
-
|
113
|
-
it 'returns true on an empty MVar' do
|
114
|
-
m = MVar.new
|
115
|
-
m.should be_empty
|
116
|
-
end
|
117
|
-
|
118
|
-
it 'returns false on a full MVar' do
|
119
|
-
m = MVar.new(14)
|
120
|
-
m.should_not be_empty
|
121
|
-
end
|
122
|
-
|
123
|
-
end
|
124
|
-
|
125
|
-
describe '#full?' do
|
126
|
-
|
127
|
-
it 'returns false on an empty MVar' do
|
128
|
-
m = MVar.new
|
129
|
-
m.should_not be_full
|
130
|
-
end
|
131
|
-
|
132
|
-
it 'returns true on a full MVar' do
|
133
|
-
m = MVar.new(14)
|
134
|
-
m.should be_full
|
135
|
-
end
|
136
|
-
|
137
|
-
end
|
138
|
-
|
139
|
-
describe '#modify' do
|
140
|
-
|
141
|
-
it 'raises an exception when no block given' do
|
142
|
-
m = MVar.new(14)
|
143
|
-
expect { m.modify }.to raise_error(ArgumentError)
|
144
|
-
end
|
145
|
-
|
146
|
-
it 'modifies a full MVar' do
|
147
|
-
m = MVar.new(14)
|
148
|
-
m.modify{ |v| v + 2 }
|
149
|
-
m.take.should eq 16
|
150
|
-
end
|
151
|
-
|
152
|
-
it 'returns the unmodified value' do
|
153
|
-
m = MVar.new(14)
|
154
|
-
m.modify{ |v| v + 2 }.should eq 14
|
155
|
-
end
|
156
|
-
|
157
|
-
it 'waits for another thread to #put' do
|
158
|
-
m = MVar.new
|
159
|
-
|
160
|
-
putter = Thread.new {
|
161
|
-
sleep(0.1)
|
162
|
-
m.put 14
|
163
|
-
}
|
164
|
-
|
165
|
-
m.modify{ |v| v + 2 }.should eq 14
|
166
|
-
end
|
167
|
-
|
168
|
-
it 'is atomic' do
|
169
|
-
m = MVar.new(0)
|
170
|
-
|
171
|
-
# #modify conceptually does #take and #put - but it should be atomic.
|
172
|
-
# Check that another #put can't sneak it during the #modify.
|
173
|
-
|
174
|
-
modifier = Thread.new {
|
175
|
-
m.modify do |v|
|
176
|
-
sleep(0.5)
|
177
|
-
1
|
178
|
-
end
|
179
|
-
}
|
180
|
-
|
181
|
-
sleep(0.1)
|
182
|
-
m.put(2, 0.5).should eq MVar::TIMEOUT
|
183
|
-
m.take.should eq 1
|
184
|
-
end
|
185
|
-
|
186
|
-
it 'returns TIMEOUT on timeout on an empty MVar' do
|
187
|
-
m = MVar.new
|
188
|
-
m.modify(0.1){ |v| v + 2 }.should eq MVar::TIMEOUT
|
189
|
-
end
|
190
|
-
|
191
|
-
end
|
192
|
-
|
193
|
-
describe '#try_put!' do
|
194
|
-
|
195
|
-
it 'returns true an empty MVar' do
|
196
|
-
m = MVar.new
|
197
|
-
m.try_put!(14).should eq true
|
198
|
-
end
|
199
|
-
|
200
|
-
it 'returns false on a full MVar' do
|
201
|
-
m = MVar.new(14)
|
202
|
-
m.try_put!(14).should eq false
|
203
|
-
end
|
204
|
-
|
205
|
-
it 'sets an empty MVar to be full' do
|
206
|
-
m = MVar.new
|
207
|
-
m.try_put! 14
|
208
|
-
m.should be_full
|
209
|
-
end
|
210
|
-
|
211
|
-
end
|
212
|
-
|
213
|
-
describe '#try_take!' do
|
214
|
-
|
215
|
-
it 'returns EMPTY an empty MVar' do
|
216
|
-
m = MVar.new
|
217
|
-
m.try_take!.should eq MVar::EMPTY
|
218
|
-
end
|
219
|
-
|
220
|
-
it 'returns the value on a full MVar' do
|
221
|
-
m = MVar.new(14)
|
222
|
-
m.try_take!.should eq 14
|
223
|
-
end
|
224
|
-
|
225
|
-
it 'sets a full MVar to be empty' do
|
226
|
-
m = MVar.new(14)
|
227
|
-
m.try_take!
|
228
|
-
m.should be_empty
|
229
|
-
end
|
230
|
-
|
231
|
-
end
|
232
|
-
|
233
|
-
describe '#set!' do
|
234
|
-
|
235
|
-
it 'sets an empty MVar to be full' do
|
236
|
-
m = MVar.new
|
237
|
-
m.set! 14
|
238
|
-
m.should be_full
|
239
|
-
end
|
240
|
-
|
241
|
-
it 'sets a full MVar to be full' do
|
242
|
-
m = MVar.new(2)
|
243
|
-
m.set! 14
|
244
|
-
m.should be_full
|
245
|
-
m.take.should eq 14
|
246
|
-
end
|
247
|
-
|
248
|
-
it 'returns EMPTY on an empty MVar' do
|
249
|
-
m = MVar.new
|
250
|
-
m.set!(2).should eq MVar::EMPTY
|
251
|
-
end
|
252
|
-
|
253
|
-
it 'returns the original value on a full MVar' do
|
254
|
-
m = MVar.new(14)
|
255
|
-
m.set!(2).should eq 14
|
256
|
-
end
|
257
|
-
|
258
|
-
end
|
259
|
-
|
260
|
-
describe '#modify!' do
|
261
|
-
|
262
|
-
it 'raises an exception when no block given' do
|
263
|
-
m = MVar.new(14)
|
264
|
-
expect { m.modify! }.to raise_error(ArgumentError)
|
265
|
-
end
|
266
|
-
|
267
|
-
it 'modifies a full MVar' do
|
268
|
-
m = MVar.new(14)
|
269
|
-
m.modify!{ |v| v + 2 }
|
270
|
-
m.take.should eq 16
|
271
|
-
end
|
272
|
-
|
273
|
-
it 'modifies an empty MVar' do
|
274
|
-
m = MVar.new
|
275
|
-
m.modify!{ |v| 14 }
|
276
|
-
m.take.should eq 14
|
277
|
-
end
|
278
|
-
|
279
|
-
it 'can be used to set a full MVar to empty' do
|
280
|
-
m = MVar.new(14)
|
281
|
-
m.modify!{ |v| MVar::EMPTY }
|
282
|
-
m.should be_empty
|
283
|
-
end
|
284
|
-
|
285
|
-
it 'can be used to set an empty MVar to empty' do
|
286
|
-
m = MVar.new
|
287
|
-
m.modify!{ |v| MVar::EMPTY }
|
288
|
-
m.should be_empty
|
289
|
-
end
|
290
|
-
|
291
|
-
it 'returns the unmodified value' do
|
292
|
-
m = MVar.new(14)
|
293
|
-
m.modify!{ |v| v + 2 }.should eq 14
|
294
|
-
end
|
295
|
-
|
296
|
-
end
|
297
|
-
|
298
|
-
context 'spurious wake ups' do
|
299
|
-
|
300
|
-
let(:m) { MVar.new }
|
301
|
-
|
302
|
-
before(:each) do
|
303
|
-
def m.simulate_spurious_wake_up
|
304
|
-
@mutex.synchronize do
|
305
|
-
@full_condition.broadcast
|
306
|
-
@empty_condition.broadcast
|
307
|
-
end
|
308
|
-
end
|
309
|
-
end
|
310
|
-
|
311
|
-
describe '#take' do
|
312
|
-
it 'waits for another thread to #put' do
|
313
|
-
Thread.new { sleep(0.5); m.put 14 }
|
314
|
-
Thread.new { sleep(0.1); m.simulate_spurious_wake_up }
|
315
|
-
|
316
|
-
m.take.should eq 14
|
317
|
-
end
|
318
|
-
|
319
|
-
it 'returns TIMEOUT on timeout on an empty MVar' do
|
320
|
-
result = nil
|
321
|
-
Thread.new { result = m.take(0.3) }
|
322
|
-
sleep(0.1)
|
323
|
-
Thread.new { m.simulate_spurious_wake_up }
|
324
|
-
sleep(0.1)
|
325
|
-
result.should be_nil
|
326
|
-
sleep(0.2)
|
327
|
-
result.should eq MVar::TIMEOUT
|
328
|
-
end
|
329
|
-
end
|
330
|
-
|
331
|
-
describe '#modify' do
|
332
|
-
|
333
|
-
it 'waits for another thread to #put' do
|
334
|
-
Thread.new { sleep(0.5); m.put 14 }
|
335
|
-
Thread.new { sleep(0.1); m.simulate_spurious_wake_up }
|
336
|
-
|
337
|
-
m.modify{ |v| v + 2 }.should eq 14
|
338
|
-
end
|
339
|
-
|
340
|
-
it 'returns TIMEOUT on timeout on an empty MVar' do
|
341
|
-
result = nil
|
342
|
-
Thread.new { result = m.modify(0.3){ |v| v + 2 } }
|
343
|
-
sleep(0.1)
|
344
|
-
Thread.new { m.simulate_spurious_wake_up }
|
345
|
-
sleep(0.1)
|
346
|
-
result.should be_nil
|
347
|
-
sleep(0.2)
|
348
|
-
result.should eq MVar::TIMEOUT
|
349
|
-
end
|
350
|
-
end
|
351
|
-
|
352
|
-
describe '#put' do
|
353
|
-
|
354
|
-
before(:each) { m.put(42) }
|
355
|
-
|
356
|
-
it 'waits for another thread to #take' do
|
357
|
-
Thread.new { sleep(0.5); m.take }
|
358
|
-
Thread.new { sleep(0.1); m.simulate_spurious_wake_up }
|
359
|
-
|
360
|
-
m.put(14).should eq 14
|
361
|
-
end
|
362
|
-
|
363
|
-
it 'returns TIMEOUT on timeout on a full MVar' do
|
364
|
-
result = nil
|
365
|
-
Thread.new { result = m.put(14, 0.3) }
|
366
|
-
sleep(0.1)
|
367
|
-
Thread.new { m.simulate_spurious_wake_up }
|
368
|
-
sleep(0.1)
|
369
|
-
result.should be_nil
|
370
|
-
sleep(0.2)
|
371
|
-
result.should eq MVar::TIMEOUT
|
372
|
-
end
|
373
|
-
end
|
374
|
-
|
375
|
-
|
376
|
-
end
|
377
|
-
|
378
|
-
end
|
379
|
-
|
380
|
-
end
|