8.9. ThreadSafeFlag¶
Az asyncio.ThreadSafeFlag az a jelzési primitív, amelyet az asyncio arra az esetre biztosít, amelyet az Event nem támogat: egy megszakításkezelőnek fel kell ébresztenie egy asyncio feladatot. A megszakítás az eseményhurok normál ütemezésén kívül lép működésbe, így az a könyvelés, amelyet az asyncio.Event.set() végez, nem hajtható végre biztonságosan belőle.
8.9.1. Miért külön primitív¶
Az asyncio.Event.set() azt a könyvelést futtatja, amely felébreszti a várakozó korutinokat, azzal a feltételezéssel, hogy egy olyan feladaton belülről hívják, amelyet a ciklus éppen futtat. Egy megszakításkezelő nem felel meg ennek a feltételezésnek – bármely két utasítás között működésbe léphet, és megronthatja azt, amivel a ciklus éppen félúton volt.
Az asyncio.ThreadSafeFlag.set() úgy van megírva, hogy biztonságos legyen ilyen kontextusokban. Ennek a biztonságnak az ára egy kisebb funkciókészlet, mint az Event esetén: egy ThreadSafeFlag-re egyszerre csak egy feladat várakozhat, és a jelző automatikusan visszaáll, amikor a várakozó feladat felébred.
8.9.2. Az alapvető alak¶
Egy tipikus felhasználás egy GPIO megszakítás, amely egy gombnyomás eseményt ad át egy asyncio feladatnak:
import asyncio
from machine import Pin
flag = asyncio.ThreadSafeFlag()
def on_press(pin):
flag.set()
async def watcher():
button = Pin("P1", Pin.IN, Pin.PULL_UP)
button.irq(handler=on_press, trigger=Pin.IRQ_FALLING)
while True:
await flag.wait()
print("button pressed")
asyncio.run(watcher())
Az on_press megszakítási kontextusban fut minden alkalommal, amikor a GPIO működésbe lép; mindössze annyit tesz, hogy meghívja a flag.set() függvényt. A watcher asyncio feladat egy ciklusban await-ol a flag.wait() hívásra; minden alkalommal, amikor a jelzőt beállítják, a feladat folytatódik, elvégzi azt a munkát, amit a gombnyomás megkövetel, majd visszatér a ciklusba újabb várakozásra.
8.9.3. A három metódus¶
set()– a jelző beállítottként jelölése. Ha egy feladat éppen await()hívásban várakozik, ütemezi annak folytatását. Biztonságosan hívható egy megszakításkezelőből.wait()– egy korutin. Addig blokkol, amíg a jelzőt be nem állítják, majd visszatér. A jelző visszatéréskor automatikusan törlődik – awaitkövetkező hívása ismét blokkolni fog a következőset()hívásig.clear()– a jelző explicit törlése anélkül, hogy várakoznánk rá. Hasznos az elsőwaitelőtt, hogy elvessünk bármely hamis koraiset()hívást, amely azelőtt lépett működésbe, hogy a feladat készen állt volna.
8.9.4. Csak egy várakozó¶
Egyszerre csak egy feladat lehet a wait() hívásban. Az az alak, amelyet egy alkalmazás szeretne, egyetlen tulajdonos feladat a jelzőhöz – általában ugyanaz a feladat, amely telepítette a megszakításkezelőt –, miközben más feladatok Event, Lock vagy az ezek a primitívek által védett megosztott adatszerkezetek révén kommunikálnak vele.
Amikor egy gombnak több feladatot kell felébresztenie, a tulajdonos feladat az a hely, ahol szétoszthat: a fenti watcher minden nyomás után meghívhatná a some_event.set() függvényt, és a some_event hívásra várakozó összes feladat folytatódna.