Skip to content

Commit ba3a121

Browse files
committed
MVar: non-blocking variants.
1 parent 242a9b7 commit ba3a121

File tree

2 files changed

+142
-0
lines changed

2 files changed

+142
-0
lines changed

lib/concurrent/mvar.rb

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,53 @@ def modify(timeout = nil)
6666
end
6767
end
6868

69+
def try_take!
70+
@mutex.synchronize do
71+
if full?
72+
value = @value
73+
@value = EMPTY
74+
@empty_condition.signal
75+
value
76+
else
77+
EMPTY
78+
end
79+
end
80+
end
81+
82+
def try_put!(value)
83+
@mutex.synchronize do
84+
if empty?
85+
@value = value
86+
@full_condition.signal
87+
true
88+
else
89+
false
90+
end
91+
end
92+
end
93+
94+
def set!(value)
95+
@mutex.synchronize do
96+
@value = value
97+
@full_condition.signal
98+
end
99+
end
100+
101+
def modify!(timeout = nil)
102+
raise ArgumentError.new('no block given') unless block_given?
103+
104+
@mutex.synchronize do
105+
value = @value
106+
@value = yield value
107+
if @value == EMPTY
108+
@empty_condition.signal
109+
else
110+
@full_condition.signal
111+
end
112+
value
113+
end
114+
end
115+
69116
def empty?
70117
@value == EMPTY
71118
end

spec/concurrent/mvar_spec.rb

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,101 @@ module Concurrent
178178

179179
end
180180

181+
context '#try_put!' do
182+
183+
it 'returns true an empty MVar' do
184+
m = MVar.new
185+
m.try_put!(14).should eq true
186+
end
187+
188+
it 'returns false on a full MVar' do
189+
m = MVar.new(14)
190+
m.try_put!(14).should eq false
191+
end
192+
193+
it 'sets an empty MVar to be full' do
194+
m = MVar.new
195+
m.try_put! 14
196+
m.should be_full
197+
end
198+
199+
end
200+
201+
context '#try_take!' do
202+
203+
it 'returns EMPTY an empty MVar' do
204+
m = MVar.new
205+
m.try_take!.should eq MVar::EMPTY
206+
end
207+
208+
it 'returns the value on a full MVar' do
209+
m = MVar.new(14)
210+
m.try_take!.should eq 14
211+
end
212+
213+
it 'sets a full MVar to be empty' do
214+
m = MVar.new(14)
215+
m.try_take!
216+
m.should be_empty
217+
end
218+
219+
end
220+
221+
context '#set!' do
222+
223+
it 'sets an empty MVar to be full' do
224+
m = MVar.new
225+
m.set! 14
226+
m.should be_full
227+
end
228+
229+
it 'sets a full MVar to be full' do
230+
m = MVar.new(2)
231+
m.set! 14
232+
m.should be_full
233+
m.take.should eq 14
234+
end
235+
236+
end
237+
238+
context '#modify!' do
239+
240+
it 'raises an exception when no block given' do
241+
m = MVar.new(14)
242+
expect { m.modify! }.to raise_error(ArgumentError)
243+
end
244+
245+
it 'modifies a full MVar' do
246+
m = MVar.new(14)
247+
m.modify!{ |v| v + 2 }
248+
m.take.should eq 16
249+
end
250+
251+
it 'modifies an empty MVar' do
252+
m = MVar.new
253+
m.modify!{ |v| 14 }
254+
m.take.should eq 14
255+
end
256+
257+
it 'can be used to set a full MVar to empty' do
258+
m = MVar.new(14)
259+
m.modify!{ |v| MVar::EMPTY }
260+
m.should be_empty
261+
end
262+
263+
it 'can be used to set an empty MVar to empty' do
264+
m = MVar.new
265+
m.modify!{ |v| MVar::EMPTY }
266+
m.should be_empty
267+
end
268+
269+
it 'returns the unmodified value' do
270+
m = MVar.new(14)
271+
m.modify!{ |v| v + 2 }.should eq 14
272+
end
273+
274+
end
275+
181276
end
182277

183278
end

0 commit comments

Comments
 (0)