summaryrefslogtreecommitdiffstats
path: root/Lib/asyncio/locks.py
diff options
context:
space:
mode:
authorGuido van Rossum <guido@dropbox.com>2013-11-04 21:18:19 (GMT)
committerGuido van Rossum <guido@dropbox.com>2013-11-04 21:18:19 (GMT)
commitccea08462b753fc78ec97cc5717de8f163b503ec (patch)
tree6f1b53396e4740b576742653dd31892311440297 /Lib/asyncio/locks.py
parentb58d4a32090185e605db4db461732393b4596b0f (diff)
downloadcpython-ccea08462b753fc78ec97cc5717de8f163b503ec.zip
cpython-ccea08462b753fc78ec97cc5717de8f163b503ec.tar.gz
cpython-ccea08462b753fc78ec97cc5717de8f163b503ec.tar.bz2
asyncio: Locks improvements by Arnaud Faure: better repr(), change Conditio\
n structure.
Diffstat (limited to 'Lib/asyncio/locks.py')
-rw-r--r--Lib/asyncio/locks.py78
1 files changed, 54 insertions, 24 deletions
diff --git a/Lib/asyncio/locks.py b/Lib/asyncio/locks.py
index 06edbbc..ac851e5 100644
--- a/Lib/asyncio/locks.py
+++ b/Lib/asyncio/locks.py
@@ -155,9 +155,11 @@ class Event:
self._loop = events.get_event_loop()
def __repr__(self):
- # TODO: add waiters:N if > 0.
res = super().__repr__()
- return '<{} [{}]>'.format(res[1:-1], 'set' if self._value else 'unset')
+ extra = 'set' if self._value else 'unset'
+ if self._waiters:
+ extra = '{},waiters:{}'.format(extra, len(self._waiters))
+ return '<{} [{}]>'.format(res[1:-1], extra)
def is_set(self):
"""Return true if and only if the internal flag is true."""
@@ -201,20 +203,38 @@ class Event:
self._waiters.remove(fut)
-# TODO: Why is this a Lock subclass? threading.Condition *has* a lock.
-class Condition(Lock):
- """A Condition implementation.
+class Condition:
+ """A Condition implementation, our equivalent to threading.Condition.
This class implements condition variable objects. A condition variable
allows one or more coroutines to wait until they are notified by another
coroutine.
+
+ A new Lock object is created and used as the underlying lock.
"""
def __init__(self, *, loop=None):
- super().__init__(loop=loop)
- self._condition_waiters = collections.deque()
+ if loop is not None:
+ self._loop = loop
+ else:
+ self._loop = events.get_event_loop()
- # TODO: Add __repr__() with len(_condition_waiters).
+ # Lock as an attribute as in threading.Condition.
+ lock = Lock(loop=self._loop)
+ self._lock = lock
+ # Export the lock's locked(), acquire() and release() methods.
+ self.locked = lock.locked
+ self.acquire = lock.acquire
+ self.release = lock.release
+
+ self._waiters = collections.deque()
+
+ def __repr__(self):
+ res = super().__repr__()
+ extra = 'locked' if self.locked() else 'unlocked'
+ if self._waiters:
+ extra = '{},waiters:{}'.format(extra, len(self._waiters))
+ return '<{} [{}]>'.format(res[1:-1], extra)
@tasks.coroutine
def wait(self):
@@ -228,19 +248,19 @@ class Condition(Lock):
the same condition variable in another coroutine. Once
awakened, it re-acquires the lock and returns True.
"""
- if not self._locked:
+ if not self.locked():
raise RuntimeError('cannot wait on un-acquired lock')
keep_lock = True
self.release()
try:
fut = futures.Future(loop=self._loop)
- self._condition_waiters.append(fut)
+ self._waiters.append(fut)
try:
yield from fut
return True
finally:
- self._condition_waiters.remove(fut)
+ self._waiters.remove(fut)
except GeneratorExit:
keep_lock = False # Prevent yield in finally clause.
@@ -275,11 +295,11 @@ class Condition(Lock):
wait() call until it can reacquire the lock. Since notify() does
not release the lock, its caller should.
"""
- if not self._locked:
+ if not self.locked():
raise RuntimeError('cannot notify on un-acquired lock')
idx = 0
- for fut in self._condition_waiters:
+ for fut in self._waiters:
if idx >= n:
break
@@ -293,7 +313,17 @@ class Condition(Lock):
calling thread has not acquired the lock when this method is called,
a RuntimeError is raised.
"""
- self.notify(len(self._condition_waiters))
+ self.notify(len(self._waiters))
+
+ def __enter__(self):
+ return self._lock.__enter__()
+
+ def __exit__(self, *args):
+ return self._lock.__exit__(*args)
+
+ def __iter__(self):
+ yield from self.acquire()
+ return self
class Semaphore:
@@ -310,10 +340,10 @@ class Semaphore:
counter; it defaults to 1. If the value given is less than 0,
ValueError is raised.
- The second optional argument determins can semophore be released more than
- initial internal counter value; it defaults to False. If the value given
- is True and number of release() is more than number of successfull
- acquire() calls ValueError is raised.
+ The second optional argument determines if the semaphore can be released
+ more than initial internal counter value; it defaults to False. If the
+ value given is True and number of release() is more than number of
+ successful acquire() calls ValueError is raised.
"""
def __init__(self, value=1, bound=False, *, loop=None):
@@ -330,12 +360,12 @@ class Semaphore:
self._loop = events.get_event_loop()
def __repr__(self):
- # TODO: add waiters:N if > 0.
res = super().__repr__()
- return '<{} [{}]>'.format(
- res[1:-1],
- 'locked' if self._locked else 'unlocked,value:{}'.format(
- self._value))
+ extra = 'locked' if self._locked else 'unlocked,value:{}'.format(
+ self._value)
+ if self._waiters:
+ extra = '{},waiters:{}'.format(extra, len(self._waiters))
+ return '<{} [{}]>'.format(res[1:-1], extra)
def locked(self):
"""Returns True if semaphore can not be acquired immediately."""
@@ -373,7 +403,7 @@ class Semaphore:
When it was zero on entry and another coroutine is waiting for it to
become larger than zero again, wake up that coroutine.
- If Semaphore is create with "bound" paramter equals true, then
+ If Semaphore is created with "bound" parameter equals true, then
release() method checks to make sure its current value doesn't exceed
its initial value. If it does, ValueError is raised.
"""