@@ -155,9 +155,11 @@ def __init__(self, *, loop=None):
155
155
self ._loop = events .get_event_loop ()
156
156
157
157
def __repr__ (self ):
158
- # TODO: add waiters:N if > 0.
159
158
res = super ().__repr__ ()
160
- return '<{} [{}]>' .format (res [1 :- 1 ], 'set' if self ._value else 'unset' )
159
+ extra = 'set' if self ._value else 'unset'
160
+ if self ._waiters :
161
+ extra = '{},waiters:{}' .format (extra , len (self ._waiters ))
162
+ return '<{} [{}]>' .format (res [1 :- 1 ], extra )
161
163
162
164
def is_set (self ):
163
165
"""Return true if and only if the internal flag is true."""
@@ -201,20 +203,38 @@ def wait(self):
201
203
self ._waiters .remove (fut )
202
204
203
205
204
- # TODO: Why is this a Lock subclass? threading.Condition *has* a lock.
205
- class Condition (Lock ):
206
- """A Condition implementation.
206
+ class Condition :
207
+ """A Condition implementation, our equivalent to threading.Condition.
207
208
208
209
This class implements condition variable objects. A condition variable
209
210
allows one or more coroutines to wait until they are notified by another
210
211
coroutine.
212
+
213
+ A new Lock object is created and used as the underlying lock.
211
214
"""
212
215
213
216
def __init__ (self , * , loop = None ):
214
- super ().__init__ (loop = loop )
215
- self ._condition_waiters = collections .deque ()
217
+ if loop is not None :
218
+ self ._loop = loop
219
+ else :
220
+ self ._loop = events .get_event_loop ()
216
221
217
- # TODO: Add __repr__() with len(_condition_waiters).
222
+ # Lock as an attribute as in threading.Condition.
223
+ lock = Lock (loop = self ._loop )
224
+ self ._lock = lock
225
+ # Export the lock's locked(), acquire() and release() methods.
226
+ self .locked = lock .locked
227
+ self .acquire = lock .acquire
228
+ self .release = lock .release
229
+
230
+ self ._waiters = collections .deque ()
231
+
232
+ def __repr__ (self ):
233
+ res = super ().__repr__ ()
234
+ extra = 'locked' if self .locked () else 'unlocked'
235
+ if self ._waiters :
236
+ extra = '{},waiters:{}' .format (extra , len (self ._waiters ))
237
+ return '<{} [{}]>' .format (res [1 :- 1 ], extra )
218
238
219
239
@tasks .coroutine
220
240
def wait (self ):
@@ -228,19 +248,19 @@ def wait(self):
228
248
the same condition variable in another coroutine. Once
229
249
awakened, it re-acquires the lock and returns True.
230
250
"""
231
- if not self ._locked :
251
+ if not self .locked () :
232
252
raise RuntimeError ('cannot wait on un-acquired lock' )
233
253
234
254
keep_lock = True
235
255
self .release ()
236
256
try :
237
257
fut = futures .Future (loop = self ._loop )
238
- self ._condition_waiters .append (fut )
258
+ self ._waiters .append (fut )
239
259
try :
240
260
yield from fut
241
261
return True
242
262
finally :
243
- self ._condition_waiters .remove (fut )
263
+ self ._waiters .remove (fut )
244
264
245
265
except GeneratorExit :
246
266
keep_lock = False # Prevent yield in finally clause.
@@ -275,11 +295,11 @@ def notify(self, n=1):
275
295
wait() call until it can reacquire the lock. Since notify() does
276
296
not release the lock, its caller should.
277
297
"""
278
- if not self ._locked :
298
+ if not self .locked () :
279
299
raise RuntimeError ('cannot notify on un-acquired lock' )
280
300
281
301
idx = 0
282
- for fut in self ._condition_waiters :
302
+ for fut in self ._waiters :
283
303
if idx >= n :
284
304
break
285
305
@@ -293,7 +313,17 @@ def notify_all(self):
293
313
calling thread has not acquired the lock when this method is called,
294
314
a RuntimeError is raised.
295
315
"""
296
- self .notify (len (self ._condition_waiters ))
316
+ self .notify (len (self ._waiters ))
317
+
318
+ def __enter__ (self ):
319
+ return self ._lock .__enter__ ()
320
+
321
+ def __exit__ (self , * args ):
322
+ return self ._lock .__exit__ (* args )
323
+
324
+ def __iter__ (self ):
325
+ yield from self .acquire ()
326
+ return self
297
327
298
328
299
329
class Semaphore :
@@ -310,10 +340,10 @@ class Semaphore:
310
340
counter; it defaults to 1. If the value given is less than 0,
311
341
ValueError is raised.
312
342
313
- The second optional argument determins can semophore be released more than
314
- initial internal counter value; it defaults to False. If the value given
315
- is True and number of release() is more than number of successfull
316
- acquire() calls ValueError is raised.
343
+ The second optional argument determines if the semaphore can be released
344
+ more than initial internal counter value; it defaults to False. If the
345
+ value given is True and number of release() is more than number of
346
+ successful acquire() calls ValueError is raised.
317
347
"""
318
348
319
349
def __init__ (self , value = 1 , bound = False , * , loop = None ):
@@ -330,12 +360,12 @@ def __init__(self, value=1, bound=False, *, loop=None):
330
360
self ._loop = events .get_event_loop ()
331
361
332
362
def __repr__ (self ):
333
- # TODO: add waiters:N if > 0.
334
363
res = super ().__repr__ ()
335
- return '<{} [{}]>' .format (
336
- res [1 :- 1 ],
337
- 'locked' if self ._locked else 'unlocked,value:{}' .format (
338
- self ._value ))
364
+ extra = 'locked' if self ._locked else 'unlocked,value:{}' .format (
365
+ self ._value )
366
+ if self ._waiters :
367
+ extra = '{},waiters:{}' .format (extra , len (self ._waiters ))
368
+ return '<{} [{}]>' .format (res [1 :- 1 ], extra )
339
369
340
370
def locked (self ):
341
371
"""Returns True if semaphore can not be acquired immediately."""
@@ -373,7 +403,7 @@ def release(self):
373
403
When it was zero on entry and another coroutine is waiting for it to
374
404
become larger than zero again, wake up that coroutine.
375
405
376
- If Semaphore is create with "bound" paramter equals true, then
406
+ If Semaphore is created with "bound" parameter equals true, then
377
407
release() method checks to make sure its current value doesn't exceed
378
408
its initial value. If it does, ValueError is raised.
379
409
"""
0 commit comments