kopia lustrzana https://github.com/peterhinch/micropython-samples
56 wiersze
1.9 KiB
Python
56 wiersze
1.9 KiB
Python
import uasyncio
|
|
|
|
################################################################################
|
|
# Lock (optional component)
|
|
|
|
# Lock class for primitive mutex capability
|
|
import uasyncio
|
|
|
|
|
|
class Lock(uasyncio.Primitive):
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._locked = False
|
|
self._awt = None # task that is going to acquire the lock. Needed to prevent race
|
|
# condition between pushing the next waiting task and the task actually acquiring
|
|
# the lock because during that time another newly started task could acquire the
|
|
# lock out-of-order instead of being pushed to the waiting list.
|
|
# Also needed to not release another waiting Task if multiple Tasks are cancelled.
|
|
|
|
async def acquire(self):
|
|
if self._locked or self._awt:
|
|
# Lock set or just released but has tasks waiting on it,
|
|
# put the calling task on the Lock's waiting queue and yield
|
|
self.save_current()
|
|
try:
|
|
yield
|
|
except uasyncio.CancelledError:
|
|
if self._awt is uasyncio.cur_task:
|
|
# Task that was going to acquire got cancelled after being scheduled.
|
|
# Schedule next waiting task
|
|
self._locked = True
|
|
self.release()
|
|
raise
|
|
self._locked = True
|
|
return True
|
|
|
|
async def __aenter__(self):
|
|
await self.acquire()
|
|
return self
|
|
|
|
def locked(self):
|
|
return self._locked
|
|
|
|
def release(self):
|
|
if not self._locked:
|
|
raise RuntimeError("Lock is not acquired.")
|
|
self._locked = False
|
|
# Lock becomes available. If task(s) are waiting on it save task which will
|
|
self._awt = self.run_next() # get lock and schedule that task
|
|
|
|
async def __aexit__(self, *args):
|
|
return self.release()
|
|
|
|
|
|
uasyncio.Lock = Lock
|