File tree Expand file tree Collapse file tree 2 files changed +73
-2
lines changed Expand file tree Collapse file tree 2 files changed +73
-2
lines changed Original file line number Diff line number Diff line change @@ -29,8 +29,6 @@ def take(timeout = nil)
29
29
TIMEOUT
30
30
end
31
31
end
32
-
33
-
34
32
end
35
33
36
34
def put ( value , timeout = nil )
@@ -49,6 +47,25 @@ def put(value, timeout = nil)
49
47
end
50
48
end
51
49
50
+ def modify ( timeout = nil )
51
+ raise ArgumentError . new ( 'no block given' ) unless block_given?
52
+
53
+ @mutex . synchronize do
54
+ # If the value isn't empty, wait for full to be signalled
55
+ @full_condition . wait ( @mutex , timeout ) if empty?
56
+
57
+ # If we timed out we'll still be empty
58
+ if full?
59
+ value = @value
60
+ @value = yield value
61
+ @full_condition . signal
62
+ value
63
+ else
64
+ TIMEOUT
65
+ end
66
+ end
67
+ end
68
+
52
69
def empty?
53
70
@value == EMPTY
54
71
end
Original file line number Diff line number Diff line change @@ -124,6 +124,60 @@ module Concurrent
124
124
125
125
end
126
126
127
+ context '#modify' do
128
+
129
+ it 'raises an exception when no block given' do
130
+ m = MVar . new ( 14 )
131
+ expect { m . modify } . to raise_error ( ArgumentError )
132
+ end
133
+
134
+ it 'modifies a full MVar' do
135
+ m = MVar . new ( 14 )
136
+ m . modify { |v | v + 2 }
137
+ m . take . should eq 16
138
+ end
139
+
140
+ it 'returns the unmodified value' do
141
+ m = MVar . new ( 14 )
142
+ m . modify { |v | v + 2 } . should eq 14
143
+ end
144
+
145
+ it 'waits for another thread to #put' do
146
+ m = MVar . new
147
+
148
+ putter = Thread . new {
149
+ sleep ( 0.5 )
150
+ m . put 14
151
+ }
152
+
153
+ m . modify { |v | v + 2 } . should eq 14
154
+ end
155
+
156
+ it 'is atomic' do
157
+ m = MVar . new ( 0 )
158
+
159
+ # #modify conceptually does #take and #put - but it should be atomic.
160
+ # Check that another #put can't sneak it during the #modify.
161
+
162
+ modifier = Thread . new {
163
+ m . modify do |v |
164
+ sleep ( 1 )
165
+ 1
166
+ end
167
+ }
168
+
169
+ sleep ( 0.5 )
170
+ m . put ( 2 , 1 ) . should eq MVar ::TIMEOUT
171
+ m . take . should eq 1
172
+ end
173
+
174
+ it 'returns TIMEOUT on timeout on an empty MVar' do
175
+ m = MVar . new
176
+ m . modify ( 0.5 ) { |v | v + 2 } . should eq MVar ::TIMEOUT
177
+ end
178
+
179
+ end
180
+
127
181
end
128
182
129
183
end
You can’t perform that action at this time.
0 commit comments