@@ -24,25 +24,23 @@ class Lock(_ContextManagerMixin, mixins._LoopBoundMixin):
24
24
"""Primitive lock objects.
25
25
26
26
A primitive lock is a synchronization primitive that is not owned
27
- by a particular coroutine when locked. A primitive lock is in one
27
+ by a particular task when locked. A primitive lock is in one
28
28
of two states, 'locked' or 'unlocked'.
29
29
30
30
It is created in the unlocked state. It has two basic methods,
31
31
acquire() and release(). When the state is unlocked, acquire()
32
32
changes the state to locked and returns immediately. When the
33
33
state is locked, acquire() blocks until a call to release() in
34
- another coroutine changes it to unlocked, then the acquire() call
34
+ another task changes it to unlocked, then the acquire() call
35
35
resets it to locked and returns. The release() method should only
36
36
be called in the locked state; it changes the state to unlocked
37
37
and returns immediately. If an attempt is made to release an
38
38
unlocked lock, a RuntimeError will be raised.
39
39
40
- When more than one coroutine is blocked in acquire() waiting for
41
- the state to turn to unlocked, only one coroutine proceeds when a
42
- release() call resets the state to unlocked; first coroutine which
43
- is blocked in acquire() is being processed.
44
-
45
- acquire() is a coroutine and should be called with 'await'.
40
+ When more than one task is blocked in acquire() waiting for
41
+ the state to turn to unlocked, only one task proceeds when a
42
+ release() call resets the state to unlocked; successive release()
43
+ calls will unblock tasks in FIFO order.
46
44
47
45
Locks also support the asynchronous context management protocol.
48
46
'async with lock' statement should be used.
@@ -130,7 +128,7 @@ def release(self):
130
128
"""Release a lock.
131
129
132
130
When the lock is locked, reset it to unlocked, and return.
133
- If any other coroutines are blocked waiting for the lock to become
131
+ If any other tasks are blocked waiting for the lock to become
134
132
unlocked, allow exactly one of them to proceed.
135
133
136
134
When invoked on an unlocked lock, a RuntimeError is raised.
@@ -182,8 +180,8 @@ def is_set(self):
182
180
return self ._value
183
181
184
182
def set (self ):
185
- """Set the internal flag to true. All coroutines waiting for it to
186
- become true are awakened. Coroutine that call wait() once the flag is
183
+ """Set the internal flag to true. All tasks waiting for it to
184
+ become true are awakened. Tasks that call wait() once the flag is
187
185
true will not block at all.
188
186
"""
189
187
if not self ._value :
@@ -194,7 +192,7 @@ def set(self):
194
192
fut .set_result (True )
195
193
196
194
def clear (self ):
197
- """Reset the internal flag to false. Subsequently, coroutines calling
195
+ """Reset the internal flag to false. Subsequently, tasks calling
198
196
wait() will block until set() is called to set the internal flag
199
197
to true again."""
200
198
self ._value = False
@@ -203,7 +201,7 @@ async def wait(self):
203
201
"""Block until the internal flag is true.
204
202
205
203
If the internal flag is true on entry, return True
206
- immediately. Otherwise, block until another coroutine calls
204
+ immediately. Otherwise, block until another task calls
207
205
set() to set the flag to true, then return True.
208
206
"""
209
207
if self ._value :
@@ -222,8 +220,8 @@ class Condition(_ContextManagerMixin, mixins._LoopBoundMixin):
222
220
"""Asynchronous equivalent to threading.Condition.
223
221
224
222
This class implements condition variable objects. A condition variable
225
- allows one or more coroutines to wait until they are notified by another
226
- coroutine .
223
+ allows one or more tasks to wait until they are notified by another
224
+ task .
227
225
228
226
A new Lock object is created and used as the underlying lock.
229
227
"""
@@ -250,50 +248,64 @@ def __repr__(self):
250
248
async def wait (self ):
251
249
"""Wait until notified.
252
250
253
- If the calling coroutine has not acquired the lock when this
251
+ If the calling task has not acquired the lock when this
254
252
method is called, a RuntimeError is raised.
255
253
256
254
This method releases the underlying lock, and then blocks
257
255
until it is awakened by a notify() or notify_all() call for
258
- the same condition variable in another coroutine . Once
256
+ the same condition variable in another task . Once
259
257
awakened, it re-acquires the lock and returns True.
258
+
259
+ This method may return spuriously,
260
+ which is why the caller should always
261
+ re-check the state and be prepared to wait() again.
260
262
"""
261
263
if not self .locked ():
262
264
raise RuntimeError ('cannot wait on un-acquired lock' )
263
265
266
+ fut = self ._get_loop ().create_future ()
264
267
self .release ()
265
268
try :
266
- fut = self ._get_loop ().create_future ()
267
- self ._waiters .append (fut )
268
269
try :
269
- await fut
270
- return True
271
- finally :
272
- self ._waiters .remove (fut )
273
-
274
- finally :
275
- # Must re-acquire lock even if wait is cancelled.
276
- # We only catch CancelledError here, since we don't want any
277
- # other (fatal) errors with the future to cause us to spin.
278
- err = None
279
- while True :
280
- try :
281
- await self .acquire ()
282
- break
283
- except exceptions .CancelledError as e :
284
- err = e
285
-
286
- if err :
270
+ self ._waiters .append (fut )
287
271
try :
288
- raise err # Re-raise most recent exception instance.
272
+ await fut
273
+ return True
289
274
finally :
290
- err = None # Break reference cycles.
275
+ self ._waiters .remove (fut )
276
+
277
+ finally :
278
+ # Must re-acquire lock even if wait is cancelled.
279
+ # We only catch CancelledError here, since we don't want any
280
+ # other (fatal) errors with the future to cause us to spin.
281
+ err = None
282
+ while True :
283
+ try :
284
+ await self .acquire ()
285
+ break
286
+ except exceptions .CancelledError as e :
287
+ err = e
288
+
289
+ if err is not None :
290
+ try :
291
+ raise err # Re-raise most recent exception instance.
292
+ finally :
293
+ err = None # Break reference cycles.
294
+ except BaseException :
295
+ # Any error raised out of here _may_ have occurred after this Task
296
+ # believed to have been successfully notified.
297
+ # Make sure to notify another Task instead. This may result
298
+ # in a "spurious wakeup", which is allowed as part of the
299
+ # Condition Variable protocol.
300
+ self ._notify (1 )
301
+ raise
291
302
292
303
async def wait_for (self , predicate ):
293
304
"""Wait until a predicate becomes true.
294
305
295
- The predicate should be a callable which result will be
296
- interpreted as a boolean value. The final predicate value is
306
+ The predicate should be a callable whose result will be
307
+ interpreted as a boolean value. The method will repeatedly
308
+ wait() until it evaluates to true. The final predicate value is
297
309
the return value.
298
310
"""
299
311
result = predicate ()
@@ -303,20 +315,22 @@ async def wait_for(self, predicate):
303
315
return result
304
316
305
317
def notify (self , n = 1 ):
306
- """By default, wake up one coroutine waiting on this condition, if any.
307
- If the calling coroutine has not acquired the lock when this method
318
+ """By default, wake up one task waiting on this condition, if any.
319
+ If the calling task has not acquired the lock when this method
308
320
is called, a RuntimeError is raised.
309
321
310
- This method wakes up at most n of the coroutines waiting for the
311
- condition variable; it is a no-op if no coroutines are waiting .
322
+ This method wakes up n of the tasks waiting for the condition
323
+ variable; if fewer than n are waiting, they are all awoken .
312
324
313
- Note: an awakened coroutine does not actually return from its
325
+ Note: an awakened task does not actually return from its
314
326
wait() call until it can reacquire the lock. Since notify() does
315
327
not release the lock, its caller should.
316
328
"""
317
329
if not self .locked ():
318
330
raise RuntimeError ('cannot notify on un-acquired lock' )
331
+ self ._notify (n )
319
332
333
+ def _notify (self , n ):
320
334
idx = 0
321
335
for fut in self ._waiters :
322
336
if idx >= n :
@@ -374,7 +388,7 @@ async def acquire(self):
374
388
375
389
If the internal counter is larger than zero on entry,
376
390
decrement it by one and return True immediately. If it is
377
- zero on entry, block, waiting until some other coroutine has
391
+ zero on entry, block, waiting until some other task has
378
392
called release() to make it larger than 0, and then return
379
393
True.
380
394
"""
@@ -414,8 +428,8 @@ async def acquire(self):
414
428
def release (self ):
415
429
"""Release a semaphore, incrementing the internal counter by one.
416
430
417
- When it was zero on entry and another coroutine is waiting for it to
418
- become larger than zero again, wake up that coroutine .
431
+ When it was zero on entry and another task is waiting for it to
432
+ become larger than zero again, wake up that task .
419
433
"""
420
434
self ._value += 1
421
435
self ._wake_up_next ()
0 commit comments