Asynchronous equivalent to threading.Condition. This class implements condition variable objects. A condition variable allows one or more tasks to wait until they are notified by another task. A new Lock object is created and used as the underlying lock.
| 217 | |
| 218 | |
| 219 | class Condition(_ContextManagerMixin, mixins._LoopBoundMixin): |
| 220 | """Asynchronous equivalent to threading.Condition. |
| 221 | |
| 222 | This class implements condition variable objects. A condition variable |
| 223 | allows one or more tasks to wait until they are notified by another |
| 224 | task. |
| 225 | |
| 226 | A new Lock object is created and used as the underlying lock. |
| 227 | """ |
| 228 | |
| 229 | def __init__(self, lock=None): |
| 230 | if lock is None: |
| 231 | lock = Lock() |
| 232 | |
| 233 | self._lock = lock |
| 234 | # Export the lock's locked(), acquire() and release() methods. |
| 235 | self.locked = lock.locked |
| 236 | self.acquire = lock.acquire |
| 237 | self.release = lock.release |
| 238 | |
| 239 | self._waiters = collections.deque() |
| 240 | |
| 241 | def __repr__(self): |
| 242 | res = super().__repr__() |
| 243 | extra = 'locked' if self.locked() else 'unlocked' |
| 244 | if self._waiters: |
| 245 | extra = f'{extra}, waiters:{len(self._waiters)}' |
| 246 | return f'<{res[1:-1]} [{extra}]>' |
| 247 | |
| 248 | async def wait(self): |
| 249 | """Wait until notified. |
| 250 | |
| 251 | If the calling task has not acquired the lock when this |
| 252 | method is called, a RuntimeError is raised. |
| 253 | |
| 254 | This method releases the underlying lock, and then blocks |
| 255 | until it is awakened by a notify() or notify_all() call for |
| 256 | the same condition variable in another task. Once |
| 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. |
| 262 | """ |
| 263 | if not self.locked(): |
| 264 | raise RuntimeError('cannot wait on un-acquired lock') |
| 265 | |
| 266 | fut = self._get_loop().create_future() |
| 267 | self.release() |
| 268 | try: |
| 269 | try: |
| 270 | self._waiters.append(fut) |
| 271 | try: |
| 272 | await fut |
| 273 | return True |
| 274 | finally: |
| 275 | self._waiters.remove(fut) |
| 276 |