@@ -92,13 +92,76 @@ module Concurrent
92
92
end
93
93
94
94
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
97
126
end
98
127
99
128
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
102
165
end
103
166
104
167
it 'raises an exception if maximum lock limit is exceeded' do
@@ -125,9 +188,26 @@ module Concurrent
125
188
expect ( counter . value ) . to eq 0
126
189
end
127
190
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
131
211
end
132
212
133
213
it 'returns true if the lock is released' do
@@ -142,15 +222,92 @@ module Concurrent
142
222
143
223
context '#acquire_write_lock' do
144
224
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 )
146
261
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
148
265
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
150
282
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
152
307
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
154
311
end
155
312
156
313
context '#release_write_lock' do
@@ -164,14 +321,48 @@ module Concurrent
164
321
expect ( counter . value ) . to eq 0
165
322
end
166
323
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
170
344
end
171
345
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
175
366
end
176
367
177
368
it 'returns true if the lock is released' do
0 commit comments