Skip to content

Commit c79a53b

Browse files
committed
Finished tests for ReadWriteLock.
1 parent 7260172 commit c79a53b

File tree

1 file changed

+209
-18
lines changed

1 file changed

+209
-18
lines changed

spec/concurrent/atomic/read_write_lock_spec.rb

Lines changed: 209 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,76 @@ module Concurrent
9292
end
9393

9494
it 'waits for a running writer to finish' do
95-
pending('need to figure out the timing')
96-
expect(true).to be false
95+
latch_1 = Concurrent::CountDownLatch.new(1)
96+
latch_2 = Concurrent::CountDownLatch.new(1)
97+
latch_3 = Concurrent::CountDownLatch.new(1)
98+
99+
write_flag = Concurrent::AtomicBoolean.new(false)
100+
read_flag = Concurrent::AtomicBoolean.new(false)
101+
102+
thread_1 = Thread.new do
103+
latch_1.wait(1)
104+
subject.acquire_write_lock
105+
latch_2.count_down
106+
latch_3.wait(1)
107+
write_flag.make_true
108+
subject.release_write_lock
109+
end
110+
111+
thread_2 = Thread.new do
112+
latch_2.wait(1)
113+
expect(write_flag.value).to be false
114+
latch_3.count_down
115+
subject.acquire_read_lock
116+
expect(write_flag.value).to be true
117+
read_flag.make_true
118+
subject.release_read_lock
119+
end
120+
121+
latch_1.count_down
122+
[thread_1, thread_2].each(&:join)
123+
124+
expect(write_flag.value).to be true
125+
expect(read_flag.value).to be true
97126
end
98127

99128
it 'does not wait for any running readers' do
100-
pending('need to figure out the timing')
101-
expect(true).to be false
129+
counter = Concurrent::Atomic.new(0)
130+
allow(Concurrent::Atomic).to receive(:new).with(anything).and_return(counter)
131+
132+
latch_1 = Concurrent::CountDownLatch.new(1)
133+
latch_2 = Concurrent::CountDownLatch.new(1)
134+
latch_3 = Concurrent::CountDownLatch.new(1)
135+
136+
read_flag_1 = Concurrent::AtomicBoolean.new(false)
137+
read_flag_2 = Concurrent::AtomicBoolean.new(false)
138+
139+
thread_1 = Thread.new do
140+
latch_1.wait(1)
141+
subject.acquire_read_lock
142+
expect(counter.value).to eq 1
143+
latch_2.count_down
144+
latch_3.wait(1)
145+
read_flag_1.make_true
146+
subject.release_read_lock
147+
end
148+
149+
thread_2 = Thread.new do
150+
latch_2.wait(1)
151+
expect(read_flag_1.value).to be false
152+
subject.acquire_read_lock
153+
expect(counter.value).to eq 2
154+
latch_3.count_down
155+
read_flag_2.make_true
156+
subject.release_read_lock
157+
end
158+
159+
latch_1.count_down
160+
[thread_1, thread_2].each(&:join)
161+
162+
expect(read_flag_1.value).to be true
163+
expect(read_flag_2.value).to be true
164+
expect(counter.value).to eq 0
102165
end
103166

104167
it 'raises an exception if maximum lock limit is exceeded' do
@@ -125,9 +188,26 @@ module Concurrent
125188
expect(counter.value).to eq 0
126189
end
127190

128-
it 'unblocks running writers' do
129-
pending('need to figure out the timing')
130-
expect(true).to be false
191+
it 'unblocks waiting writers' do
192+
latch_1 = Concurrent::CountDownLatch.new(1)
193+
latch_2 = Concurrent::CountDownLatch.new(1)
194+
write_flag = Concurrent::AtomicBoolean.new(false)
195+
196+
thread = Thread.new do
197+
latch_1.wait(1)
198+
latch_2.count_down
199+
subject.acquire_write_lock
200+
write_flag.make_true
201+
subject.release_write_lock
202+
end
203+
204+
subject.acquire_read_lock
205+
latch_1.count_down
206+
latch_2.wait(1)
207+
expect(write_flag.value).to be false
208+
subject.release_read_lock
209+
thread.join
210+
expect(write_flag.value).to be true
131211
end
132212

133213
it 'returns true if the lock is released' do
@@ -142,15 +222,92 @@ module Concurrent
142222

143223
context '#acquire_write_lock' do
144224

145-
it 'increments the lock count'
225+
it 'increments the lock count' do
226+
counter = Concurrent::Atomic.new(0)
227+
allow(Concurrent::Atomic).to receive(:new).with(anything).and_return(counter)
228+
subject.acquire_write_lock
229+
expect(counter.value).to be > 1
230+
end
231+
232+
it 'waits for a running writer to finish' do
233+
latch_1 = Concurrent::CountDownLatch.new(1)
234+
latch_2 = Concurrent::CountDownLatch.new(1)
235+
latch_3 = Concurrent::CountDownLatch.new(1)
236+
237+
write_flag_1 = Concurrent::AtomicBoolean.new(false)
238+
write_flag_2 = Concurrent::AtomicBoolean.new(false)
239+
240+
thread_1 = Thread.new do
241+
latch_1.wait(1)
242+
subject.acquire_write_lock
243+
latch_2.count_down
244+
latch_3.wait(1)
245+
write_flag_1.make_true
246+
subject.release_write_lock
247+
end
248+
249+
thread_2 = Thread.new do
250+
latch_2.wait(1)
251+
expect(write_flag_1.value).to be false
252+
latch_3.count_down
253+
subject.acquire_write_lock
254+
expect(write_flag_1.value).to be true
255+
write_flag_2.make_true
256+
subject.release_write_lock
257+
end
258+
259+
latch_1.count_down
260+
[thread_1, thread_2].each(&:join)
146261

147-
it 'waits for a running writer to finish'
262+
expect(write_flag_1.value).to be true
263+
expect(write_flag_2.value).to be true
264+
end
148265

149-
it 'waits for a running reader to finish'
266+
it 'waits for a running reader to finish' do
267+
latch_1 = Concurrent::CountDownLatch.new(1)
268+
latch_2 = Concurrent::CountDownLatch.new(1)
269+
latch_3 = Concurrent::CountDownLatch.new(1)
270+
271+
read_flag = Concurrent::AtomicBoolean.new(false)
272+
write_flag = Concurrent::AtomicBoolean.new(false)
273+
274+
thread_1 = Thread.new do
275+
latch_1.wait(1)
276+
subject.acquire_read_lock
277+
latch_2.count_down
278+
latch_3.wait(1)
279+
read_flag.make_true
280+
subject.release_read_lock
281+
end
150282

151-
it 'raises an exception if maximum lock limit is exceeded'
283+
thread_2 = Thread.new do
284+
latch_2.wait(1)
285+
expect(read_flag.value).to be false
286+
latch_3.count_down
287+
subject.acquire_write_lock
288+
expect(read_flag.value).to be true
289+
write_flag.make_true
290+
subject.release_write_lock
291+
end
292+
293+
latch_1.count_down
294+
[thread_1, thread_2].each(&:join)
295+
296+
expect(read_flag.value).to be true
297+
expect(write_flag.value).to be true
298+
end
299+
300+
it 'raises an exception if maximum lock limit is exceeded' do
301+
counter = Concurrent::Atomic.new(ReadWriteLock::MAX_WRITERS)
302+
allow(Concurrent::Atomic).to receive(:new).with(anything).and_return(counter)
303+
expect {
304+
subject.acquire_write_lock { nil }
305+
}.to raise_error(Concurrent::ResourceLimitError)
306+
end
152307

153-
it 'returns true if the lock is acquired'
308+
it 'returns true if the lock is acquired' do
309+
expect(subject.acquire_write_lock).to be true
310+
end
154311
end
155312

156313
context '#release_write_lock' do
@@ -164,14 +321,48 @@ module Concurrent
164321
expect(counter.value).to eq 0
165322
end
166323

167-
it 'unblocks running readers' do
168-
pending('need to figure out the timing')
169-
expect(true).to be false
324+
it 'unblocks waiting readers' do
325+
latch_1 = Concurrent::CountDownLatch.new(1)
326+
latch_2 = Concurrent::CountDownLatch.new(1)
327+
read_flag = Concurrent::AtomicBoolean.new(false)
328+
329+
thread = Thread.new do
330+
latch_1.wait(1)
331+
latch_2.count_down
332+
subject.acquire_read_lock
333+
read_flag.make_true
334+
subject.release_read_lock
335+
end
336+
337+
subject.acquire_write_lock
338+
latch_1.count_down
339+
latch_2.wait(1)
340+
expect(read_flag.value).to be false
341+
subject.release_write_lock
342+
thread.join
343+
expect(read_flag.value).to be true
170344
end
171345

172-
it 'unblocks running writers' do
173-
pending('need to figure out the timing')
174-
expect(true).to be false
346+
it 'unblocks waiting writers' do
347+
latch_1 = Concurrent::CountDownLatch.new(1)
348+
latch_2 = Concurrent::CountDownLatch.new(1)
349+
write_flag = Concurrent::AtomicBoolean.new(false)
350+
351+
thread = Thread.new do
352+
latch_1.wait(1)
353+
latch_2.count_down
354+
subject.acquire_write_lock
355+
write_flag.make_true
356+
subject.release_write_lock
357+
end
358+
359+
subject.acquire_write_lock
360+
latch_1.count_down
361+
latch_2.wait(1)
362+
expect(write_flag.value).to be false
363+
subject.release_write_lock
364+
thread.join
365+
expect(write_flag.value).to be true
175366
end
176367

177368
it 'returns true if the lock is released' do

0 commit comments

Comments
 (0)